"""Agent account storage. Passwords are hashed; never stored in plain text."""

from __future__ import annotations

import json
import re
import threading
import uuid
from datetime import datetime, timezone
from pathlib import Path

from werkzeug.security import check_password_hash, generate_password_hash

DATA_DIR = Path(__file__).resolve().parent / "data"
ACCOUNTS_PATH = DATA_DIR / "agent_accounts.json"
LOCK = threading.Lock()
EMAIL_RE = re.compile(r"^[^@\s]+@[^@\s]+\.[^@\s]+$")


def _load() -> list[dict]:
    if not ACCOUNTS_PATH.exists():
        return []
    try:
        return json.loads(ACCOUNTS_PATH.read_text(encoding="utf-8"))
    except json.JSONDecodeError:
        return []


def _save(rows: list[dict]) -> None:
    DATA_DIR.mkdir(parents=True, exist_ok=True)
    tmp = ACCOUNTS_PATH.with_suffix(".json.tmp")
    tmp.write_text(json.dumps(rows, indent=2), encoding="utf-8")
    tmp.replace(ACCOUNTS_PATH)


def find_by_email(email: str) -> dict | None:
    email_n = (email or "").strip().lower()
    with LOCK:
        for row in _load():
            if row.get("email", "").lower() == email_n:
                return row
    return None


def find_by_id(user_id: str) -> dict | None:
    with LOCK:
        for row in _load():
            if row.get("id") == user_id:
                return row
    return None


def public_user(row: dict) -> dict:
    return {
        "id": row["id"],
        "first_name": row.get("first_name", ""),
        "last_name": row.get("last_name", ""),
        "email": row.get("email", ""),
        "phone": row.get("phone", ""),
        "license_status": row.get("license_status", ""),
        "created_at": row.get("created_at", ""),
    }


def register(data: dict) -> tuple[dict | None, dict[str, str]]:
    errors: dict[str, str] = {}
    first = (data.get("first_name") or "").strip()
    last = (data.get("last_name") or "").strip()
    email = (data.get("email") or "").strip().lower()
    phone = (data.get("phone") or "").strip()
    license_status = (data.get("license_status") or "").strip()
    password = data.get("password") or ""
    confirm = data.get("password_confirm") or ""
    if not first:
        errors["first_name"] = "This field is required."
    if not last:
        errors["last_name"] = "This field is required."
    if not email or not EMAIL_RE.match(email):
        errors["email"] = "Enter an email address in the format name@example.com."
    if len(re.sub(r"\D", "", phone)) < 10:
        errors["phone"] = "Enter a 10-digit U.S. phone number."
    if not license_status:
        errors["license_status"] = "Choose a license status."
    if len(password) < 10:
        errors["password"] = "Use at least 10 characters."
    if password != confirm:
        errors["password_confirm"] = "Passwords do not match."
    if errors:
        return None, errors
    with LOCK:
        rows = _load()
        if any(row.get("email", "").lower() == email for row in rows):
            return None, {"email": "An account with this email already exists. Try signing in."}
        row = {
            "id": str(uuid.uuid4()),
            "first_name": first,
            "last_name": last,
            "email": email,
            "phone": phone,
            "license_status": license_status,
            "password_hash": generate_password_hash(password),
            "created_at": datetime.now(timezone.utc).isoformat(),
        }
        rows.append(row)
        _save(rows)
        return public_user(row), {}


def authenticate(email: str, password: str) -> dict | None:
    row = find_by_email(email)
    if not row:
        return None
    if not check_password_hash(row.get("password_hash", ""), password or ""):
        return None
    return public_user(row)
