from __future__ import annotations

import json
import time
from pathlib import Path
from typing import Any

import pandas as pd

from web_core.auth.profile_auth import (
    DEFAULT_PROFILE_ID,
    PROFILE_SESSION_TIMEOUT_SEC,
    find_existing_profile_id,
    first_query_param_value,
    hash_profile_pin,
    is_truthy_flag,
    is_profile_session_expired,
    normalize_pin,
    normalize_profile_id,
    profile_exists,
    resolve_login_profile,
)
from web_core.settings.settings_schema import normalize_web_settings
from web_core.time_display import format_timestamp

SETTINGS_PATH = Path.home() / ".web_local_shell" / "settings.json"
LEGACY_SETTINGS_PATH = Path.home() / ".manesh_trader" / "settings.json"


def _normalize_epoch(value: Any) -> int | None:
    if not isinstance(value, (int, float)):
        return None
    parsed = int(value)
    return parsed if parsed >= 0 else None


def format_epoch(
    value: Any,
    display_timezone: str = "America/Chicago",
    use_24h_time: bool = False,
) -> str:
    parsed = _normalize_epoch(value)
    if parsed is None:
        return "n/a"
    return format_timestamp(
        pd.to_datetime(parsed, unit="s", utc=True),
        display_timezone=display_timezone,
        use_24h_time=use_24h_time,
    )


def _load_raw_settings_payload() -> dict[str, Any] | None:
    source_path = SETTINGS_PATH if SETTINGS_PATH.exists() else LEGACY_SETTINGS_PATH
    if not source_path.exists():
        return None
    try:
        payload = json.loads(source_path.read_text(encoding="utf-8"))
        return payload if isinstance(payload, dict) else None
    except Exception:
        return None


def normalize_profile_record(profile_id: str, raw_profile_data: Any) -> dict[str, Any]:
    now_epoch = int(time.time())
    fallback_settings = normalize_web_settings(None)
    settings: dict[str, Any]
    pin_hash = ""
    raw_audit: Any = {}

    if isinstance(raw_profile_data, dict) and isinstance(raw_profile_data.get("settings"), dict):
        settings = normalize_web_settings(raw_profile_data.get("settings"))
        pin_hash = str(raw_profile_data.get("pin_hash") or "").strip()
        if not pin_hash and isinstance(raw_profile_data.get("auth"), dict):
            pin_hash = str(raw_profile_data["auth"].get("pin_hash") or "").strip()
        raw_audit = raw_profile_data.get("audit")
    elif isinstance(raw_profile_data, dict):
        settings = normalize_web_settings(raw_profile_data)
    else:
        settings = fallback_settings

    created_at = now_epoch
    updated_at = now_epoch
    last_login_at = None
    last_symbol = str(settings.get("symbol", fallback_settings["symbol"]))
    if isinstance(raw_audit, dict):
        created_at = _normalize_epoch(raw_audit.get("created_at")) or now_epoch
        updated_at = _normalize_epoch(raw_audit.get("updated_at")) or created_at
        last_login_at = _normalize_epoch(raw_audit.get("last_login_at"))
        raw_last_symbol = str(raw_audit.get("last_symbol") or "").strip().upper()
        if raw_last_symbol:
            last_symbol = raw_last_symbol

    return {
        "settings": settings,
        "pin_hash": pin_hash,
        "audit": {
            "created_at": created_at,
            "updated_at": updated_at,
            "last_login_at": last_login_at,
            "last_symbol": last_symbol,
        },
    }


def _write_settings_store(profile_records: dict[str, dict[str, Any]], last_profile: str) -> None:
    serialized_profiles: dict[str, dict[str, Any]] = {}
    for profile_id, record in profile_records.items():
        serialized_profiles[profile_id] = normalize_profile_record(profile_id=profile_id, raw_profile_data=record)

    payload = {
        "last_profile": normalize_profile_id(last_profile),
        "profiles": serialized_profiles,
    }
    SETTINGS_PATH.parent.mkdir(parents=True, exist_ok=True)
    SETTINGS_PATH.write_text(json.dumps(payload, indent=2), encoding="utf-8")


def _load_profile_records() -> tuple[dict[str, dict[str, Any]], str]:
    payload = _load_raw_settings_payload()
    if not payload:
        return {}, DEFAULT_PROFILE_ID

    raw_profiles = payload.get("profiles")
    if isinstance(raw_profiles, dict):
        profile_records: dict[str, dict[str, Any]] = {}
        for raw_profile_id, raw_profile_data in raw_profiles.items():
            if isinstance(raw_profile_data, dict):
                profile_id = normalize_profile_id(raw_profile_id)
                profile_records[profile_id] = normalize_profile_record(profile_id, raw_profile_data)

        last_profile = normalize_profile_id(payload.get("last_profile"))
        if profile_records and last_profile not in profile_records:
            last_profile = next(iter(profile_records))
        return profile_records, last_profile

    legacy_record = normalize_profile_record(profile_id=DEFAULT_PROFILE_ID, raw_profile_data=payload)
    return {DEFAULT_PROFILE_ID: legacy_record}, DEFAULT_PROFILE_ID


def list_web_profiles() -> list[str]:
    profile_records, _ = _load_profile_records()
    profile_ids = list(profile_records.keys())
    if DEFAULT_PROFILE_ID not in profile_ids:
        profile_ids.append(DEFAULT_PROFILE_ID)
    return sorted(profile_ids, key=lambda item: (item != DEFAULT_PROFILE_ID, item.lower()))


def load_web_settings(profile_id: str | None = None) -> dict[str, Any]:
    profile_records, last_profile = _load_profile_records()
    selected_profile = normalize_profile_id(profile_id if profile_id is not None else last_profile)
    if selected_profile not in profile_records:
        return normalize_web_settings(None)
    return normalize_web_settings(profile_records[selected_profile].get("settings"))


def profile_requires_pin(profile_id: str) -> bool:
    selected = normalize_profile_id(profile_id)
    profile_records, _ = _load_profile_records()
    record = profile_records.get(selected)
    return isinstance(record, dict) and bool(str(record.get("pin_hash") or "").strip())


def verify_profile_pin(profile_id: str, pin: Any) -> bool:
    selected = normalize_profile_id(profile_id)
    profile_records, _ = _load_profile_records()
    record = profile_records.get(selected)
    if not isinstance(record, dict):
        return False

    stored_hash = str(record.get("pin_hash") or "").strip()
    if not stored_hash:
        return True

    normalized_pin = normalize_pin(pin)
    if normalized_pin is None:
        return False
    return stored_hash == hash_profile_pin(selected, normalized_pin)


def get_profile_audit(profile_id: str) -> dict[str, Any]:
    selected = normalize_profile_id(profile_id)
    profile_records, _ = _load_profile_records()
    record = profile_records.get(selected)
    if not isinstance(record, dict):
        return {}
    audit = record.get("audit")
    return audit if isinstance(audit, dict) else {}


def create_profile(profile_id: str, pin: Any = None, now_epoch: int | None = None) -> None:
    selected = normalize_profile_id(profile_id)
    profile_records, _ = _load_profile_records()
    epoch = int(now_epoch if now_epoch is not None else time.time())
    normalized_pin = normalize_pin(pin)

    profile_records[selected] = {
        "settings": normalize_web_settings(None),
        "pin_hash": hash_profile_pin(selected, normalized_pin) if normalized_pin else "",
        "audit": {
            "created_at": epoch,
            "updated_at": epoch,
            "last_login_at": epoch,
            "last_symbol": "AAPL",
        },
    }
    _write_settings_store(profile_records, last_profile=selected)


def mark_profile_login(profile_id: str, now_epoch: int | None = None) -> None:
    selected = normalize_profile_id(profile_id)
    profile_records, _ = _load_profile_records()
    epoch = int(now_epoch if now_epoch is not None else time.time())
    existing = profile_records.get(selected, normalize_profile_record(selected, {}))
    normalized = normalize_profile_record(selected, existing)
    normalized["audit"]["last_login_at"] = epoch
    profile_records[selected] = normalized
    _write_settings_store(profile_records, last_profile=selected)


def save_web_settings(settings: dict[str, Any], profile_id: str | None = None) -> None:
    selected_profile = normalize_profile_id(profile_id)
    now_epoch = int(time.time())
    profile_records, _ = _load_profile_records()
    existing = profile_records.get(selected_profile, normalize_profile_record(selected_profile, {}))
    normalized_existing = normalize_profile_record(selected_profile, existing)
    normalized_settings = normalize_web_settings(settings)

    normalized_existing["settings"] = normalized_settings
    normalized_existing["audit"]["updated_at"] = now_epoch
    normalized_existing["audit"]["last_symbol"] = str(normalized_settings.get("symbol", "AAPL"))
    profile_records[selected_profile] = normalized_existing
    _write_settings_store(profile_records, last_profile=selected_profile)
