from __future__ import annotations

import json
from typing import Any

from common.runtime_paths import app_data_root
from common.task_runtime import account_fingerprint

_HISTORY_KEY = "__credential_history__"


def _history_unique_key(cloud_key: str, mark: str, ak: str, sk: str) -> str:
    if cloud_key == "ctyun":
        return account_fingerprint(ak, sk)
    return mark


def _cache_path():
    path = app_data_root() / "credential_marks.json"
    path.parent.mkdir(parents=True, exist_ok=True)
    return path


def _load_cache() -> dict[str, Any]:
    path = _cache_path()
    if not path.exists():
        return {}
    try:
        data = json.loads(path.read_text(encoding="utf-8"))
    except Exception:
        return {}
    return data if isinstance(data, dict) else {}


def _save_cache(data: dict[str, Any]) -> None:
    path = _cache_path()
    tmp = path.with_suffix(".tmp")
    tmp.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
    tmp.replace(path)


def cached_mark_for_credentials(cloud: str, ak: str, sk: str) -> str:
    cloud_key = (cloud or "").strip().lower()
    if not cloud_key or not (ak or "").strip() or not (sk or "").strip():
        return ""
    data = _load_cache()
    cloud_data = data.get(cloud_key)
    if not isinstance(cloud_data, dict):
        return ""
    value = cloud_data.get(account_fingerprint(ak, sk))
    return str(value or "").strip()


def credential_history_for_cloud(cloud: str) -> list[dict[str, str]]:
    """Return recent local credential records for a cloud, newest first."""
    cloud_key = (cloud or "").strip().lower()
    if not cloud_key:
        return []
    data = _load_cache()
    cloud_data = data.get(cloud_key)
    if not isinstance(cloud_data, dict):
        return []
    history = cloud_data.get(_HISTORY_KEY)
    if not isinstance(history, list):
        return []
    records: list[dict[str, str]] = []
    seen_records: set[str] = set()
    for item in history:
        if not isinstance(item, dict):
            continue
        mark = str(item.get("mark") or "").strip()
        ak = str(item.get("ak") or "").strip()
        sk = str(item.get("sk") or "").strip()
        unique_key = _history_unique_key(cloud_key, mark, ak, sk)
        if not mark or not ak or not sk or unique_key in seen_records:
            continue
        records.append({"mark": mark[:80], "ak": ak, "sk": sk})
        seen_records.add(unique_key)
    return records


def delete_credential_history_record(cloud: str, mark: str, ak: str = "", sk: str = "") -> bool:
    """Remove one local credential history record from the quick-select list."""
    cloud_key = (cloud or "").strip().lower()
    mark_value = str(mark or "").strip()[:80]
    ak_value = str(ak or "").strip()
    sk_value = str(sk or "").strip()
    if not cloud_key or not mark_value:
        return False
    data = _load_cache()
    cloud_data = data.get(cloud_key)
    if not isinstance(cloud_data, dict):
        return False
    history = cloud_data.get(_HISTORY_KEY)
    if not isinstance(history, list):
        return False

    removed = False
    next_history: list[dict[str, str]] = []
    for item in history:
        if not isinstance(item, dict):
            continue
        old_mark = str(item.get("mark") or "").strip()[:80]
        old_ak = str(item.get("ak") or "").strip()
        old_sk = str(item.get("sk") or "").strip()
        same_mark = old_mark == mark_value
        same_credentials = bool(ak_value and sk_value and old_ak == ak_value and old_sk == sk_value)
        if cloud_key == "ctyun" and ak_value and sk_value:
            should_remove = same_credentials
        else:
            should_remove = same_mark or same_credentials
        if should_remove:
            removed = True
            continue
        next_history.append(item)
    if not removed:
        return False

    cloud_data[_HISTORY_KEY] = next_history
    if ak_value and sk_value:
        cloud_data.pop(account_fingerprint(ak_value, sk_value), None)
    if cloud_key != "ctyun" or not (ak_value and sk_value):
        for key, value in list(cloud_data.items()):
            if key != _HISTORY_KEY and str(value or "").strip()[:80] == mark_value:
                cloud_data.pop(key, None)
    _save_cache(data)
    return True


def remember_mark_for_credentials(cloud: str, ak: str, sk: str, mark: str) -> None:
    """Save the resolved Mark and local credential history for quick reuse."""
    cloud_key = (cloud or "").strip().lower()
    mark_value = str(mark or "").strip()
    ak_value = str(ak or "").strip()
    sk_value = str(sk or "").strip()
    if not cloud_key or not mark_value or not ak_value or not sk_value:
        return
    data = _load_cache()
    cloud_data = data.get(cloud_key)
    if not isinstance(cloud_data, dict):
        cloud_data = {}
        data[cloud_key] = cloud_data
    mark_value = mark_value[:80]
    cloud_data[account_fingerprint(ak_value, sk_value)] = mark_value
    history = cloud_data.get(_HISTORY_KEY)
    if not isinstance(history, list):
        history = []
    next_history: list[dict[str, str]] = [{"mark": mark_value, "ak": ak_value, "sk": sk_value}]
    seen_records = {_history_unique_key(cloud_key, mark_value, ak_value, sk_value)}
    for item in history:
        if not isinstance(item, dict):
            continue
        old_mark = str(item.get("mark") or "").strip()[:80]
        old_ak = str(item.get("ak") or "").strip()
        old_sk = str(item.get("sk") or "").strip()
        old_unique_key = _history_unique_key(cloud_key, old_mark, old_ak, old_sk)
        if not old_mark or not old_ak or not old_sk or old_unique_key in seen_records:
            continue
        if old_ak == ak_value and old_sk == sk_value:
            continue
        next_history.append({"mark": old_mark, "ak": old_ak, "sk": old_sk})
        seen_records.add(old_unique_key)
    cloud_data[_HISTORY_KEY] = next_history
    _save_cache(data)
