from __future__ import annotations

from pathlib import Path
from sqlite3 import Connection

from .common import ImportResult, clean, create_import_session, parse_bool, require_text, source_hash, stable_id, utc_now
from .dry_run import read_csv_rows

REQUIRED_COLUMNS = {"platform_name", "platform_type", "account_name", "account_type", "currency"}


def _existing_account(conn: Connection, platform_id: str, account_name: str) -> bool:
    row = conn.execute(
        "SELECT 1 FROM accounts WHERE platform_id = ? AND account_name = ? LIMIT 1",
        (platform_id, account_name),
    ).fetchone()
    return row is not None


def import_accounts_csv(
    conn: Connection,
    path: str | Path,
    *,
    commit: bool,
    source_filename: str | None = None,
) -> ImportResult:
    rows, errors = read_csv_rows(path, REQUIRED_COLUMNS)
    source_filename = source_filename or Path(path).name
    rows_new = rows_existing = 0
    validated: list[dict[str, str | bool | int]] = []
    for line, row in enumerate(rows, start=2):
        try:
            platform_name = require_text(row, "platform_name", line)
            platform_type = require_text(row, "platform_type", line)
            account_name = require_text(row, "account_name", line)
            account_type = require_text(row, "account_type", line)
            currency = require_text(row, "currency", line).upper()
            platform_id = stable_id("platform", platform_name)
            account_id = stable_id("account", platform_name, account_name)
            if _existing_account(conn, platform_id, account_name):
                rows_existing += 1
            else:
                rows_new += 1
            # Generic bank/CSV imports cannot classify investment roles. Parse the
            # legacy column for validation only, then keep the new account excluded.
            parse_bool(row.get("performance_included"), False)
            validated.append({
                "platform_id": platform_id,
                "account_id": account_id,
                "platform_name": platform_name,
                "platform_type": platform_type,
                "account_name": account_name,
                "account_type": account_type,
                "currency": currency,
                "performance_included": False,
                "is_health_reserve": parse_bool(row.get("is_health_reserve"), False),
                "notes": clean(row.get("notes")),
            })
        except ValueError as exc:
            errors.append(str(exc))
    status = "failed" if errors else ("committed" if commit else "dry_run_ok")
    if commit and not errors:
        now = utc_now()
        for item in validated:
            conn.execute(
                """
                INSERT OR IGNORE INTO platforms(platform_id, name, platform_type, default_currency, notes, created_at)
                VALUES (?, ?, ?, ?, ?, ?)
                """,
                (item["platform_id"], item["platform_name"], item["platform_type"], item["currency"], item["notes"], now),
            )
            conn.execute(
                """
                INSERT OR IGNORE INTO accounts(
                    account_id, platform_id, account_name, account_type, currency,
                    performance_included, is_health_reserve, notes, created_at
                ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
                """,
                (
                    item["account_id"], item["platform_id"], item["account_name"], item["account_type"],
                    item["currency"], item["performance_included"], item["is_health_reserve"], item["notes"], now,
                ),
            )
    session_id = create_import_session(
        conn,
        import_type="accounts",
        source_filename=source_filename,
        file_hash=source_hash(path),
        status=status,
        rows_total=len(rows),
        rows_imported=rows_new if commit and not errors else 0,
        rows_failed=len(errors),
        errors=errors,
        notes="dry run" if not commit else None,
    )
    return ImportResult(session_id, "accounts", status, len(rows), rows_new if not errors else 0, rows_existing, len(errors), errors)
