import time
import json
import frappe

BASE_URL = "https://my.birbank.business/api/b2b"


class KapitalBankAPITest(frappe.model.document.Document):
    pass


# ─────────────────────────────────────────────────────────────────────────────
# Helpers
# ─────────────────────────────────────────────────────────────────────────────

def _dump_get(path, params=None):
    """Build human-readable GET request dump."""
    url = f"{BASE_URL}{path}"
    if params:
        clean = {k: v for k, v in params.items() if v is not None}
        qs = "&".join(f"{k}={v}" for k, v in clean.items())
        lines = [f"GET {url}", f"Params: {json.dumps(clean, indent=2, ensure_ascii=False)}"]
    else:
        lines = [f"GET {url}"]
    return "\n".join(lines)


def _dump_post(path, body=None):
    """Build human-readable POST request dump."""
    url = f"{BASE_URL}{path}"
    lines = [f"POST {url}"]
    if body:
        lines.append(f"Body: {json.dumps(body, indent=2, ensure_ascii=False)}")
    return "\n".join(lines)


def _is_success(data):
    """Detect success from both auth-wrapper dicts and raw bank responses."""
    if not data:
        return False
    if "success" in data:
        return bool(data["success"])
    code = data.get("response", {}).get("code")
    if code is not None:
        return str(code) == "0"
    return True


def _finish(docname, data, elapsed_ms, request_dump=""):
    """Persist result + request dump to the doc and return a uniform response dict."""
    status = "Success" if _is_success(data) else "Failed"
    result_json = json.dumps(data, indent=2, ensure_ascii=False, default=str)
    frappe.db.set_value("Kapital Bank API Test", docname, {
        "request_dump": request_dump,
        "result": result_json,
        "test_status": status,
        "response_time_ms": elapsed_ms,
    }, update_modified=False)
    frappe.db.commit()
    return {"status": status, "result": result_json, "elapsed_ms": elapsed_ms}


def _run(docname, fn, request_dump=""):
    """Call fn(), measure time, persist result, return response dict."""
    start = time.time()
    try:
        data = fn()
    except Exception as e:
        frappe.log_error(
            f"API Test [{docname}]: {e}\n{frappe.get_traceback()}",
            "KB API Test"
        )
        data = {"success": False, "message": str(e)}
    return _finish(docname, data, int((time.time() - start) * 1000), request_dump)


# ─────────────────────────────────────────────────────────────────────────────
# Auth
# ─────────────────────────────────────────────────────────────────────────────

@frappe.whitelist()
def do_login(docname):
    doc = frappe.get_doc("Kapital Bank API Test", docname)
    login_doc = frappe.get_doc("Kapital Bank Login", doc.login_name)
    req = _dump_post("/login", {"username": login_doc.username, "password": "***"})
    from kapital_bank.auth import login
    return _run(docname, lambda: login(doc.login_name), req)


@frappe.whitelist()
def do_logout(docname):
    doc = frappe.get_doc("Kapital Bank API Test", docname)
    req = "(local operation — clears tokens in DB, no HTTP request to bank)"
    from kapital_bank.auth import logout
    return _run(docname, lambda: logout(doc.login_name), req)


@frappe.whitelist()
def do_refresh_token(docname):
    doc = frappe.get_doc("Kapital Bank API Test", docname)
    req = _dump_post("/refresh", {"refreshToken": "***"})
    from kapital_bank.auth import renew_token
    return _run(docname, lambda: renew_token(doc.login_name), req)


# ─────────────────────────────────────────────────────────────────────────────
# Accounts
# ─────────────────────────────────────────────────────────────────────────────

@frappe.whitelist()
def do_get_accounts(docname):
    doc = frappe.get_doc("Kapital Bank API Test", docname)
    from kapital_bank.api import BIRBankClient
    req = _dump_get("/b2b/accounts/portal/v1")
    def _call():
        return BIRBankClient(doc.login_name).get_json("/b2b/accounts/portal/v1")
    return _run(docname, _call, req)


@frappe.whitelist()
def do_get_account_statement(docname):
    doc = frappe.get_doc("Kapital Bank API Test", docname)
    from kapital_bank.api import BIRBankClient
    params = {
        "accountNumber": doc.iban,
        "fromDate": str(doc.from_date) if doc.from_date else None,
        "toDate": str(doc.to_date) if doc.to_date else None,
    }
    req = _dump_get("/b2b/account/portal/v3/statements", params)
    def _call():
        return BIRBankClient(doc.login_name).get_json("/b2b/account/portal/v3/statements", params=params)
    return _run(docname, _call, req)


# ─────────────────────────────────────────────────────────────────────────────
# Cards
# ─────────────────────────────────────────────────────────────────────────────

@frappe.whitelist()
def do_get_cards(docname):
    doc = frappe.get_doc("Kapital Bank API Test", docname)
    from kapital_bank.api import BIRBankClient
    req = _dump_get("/b2b/cards/portal/v1")
    def _call():
        return BIRBankClient(doc.login_name).get_json("/b2b/cards/portal/v1")
    return _run(docname, _call, req)


@frappe.whitelist()
def do_get_card_statement(docname):
    import re
    doc = frappe.get_doc("Kapital Bank API Test", docname)
    from kapital_bank.api import BIRBankClient
    pan = frappe.db.get_value("Kapital Bank Card", doc.account_number, "pan") or ""
    params = {
        "accountNo": doc.account_number,
        "panLast4": re.sub(r"\D", "", pan)[-4:],
        "dateFrom": str(doc.from_date) if doc.from_date else None,
        "dateTo": str(doc.to_date) if doc.to_date else None,
        "pageId": 0,
    }
    req = _dump_get("/b2b/cards/portal/v1/statements", params)
    def _call():
        return BIRBankClient(doc.login_name).get_json("/b2b/cards/portal/v1/statements", params=params)
    return _run(docname, _call, req)


# ─────────────────────────────────────────────────────────────────────────────
# Payments
# ─────────────────────────────────────────────────────────────────────────────

@frappe.whitelist()
def do_transfer_status(docname):
    doc = frappe.get_doc("Kapital Bank API Test", docname)
    from kapital_bank.api import BIRBankClient
    transfer_id = (doc.operation_name_param or "").strip()
    path = f"/b2b/transfers/portal/v1/{transfer_id}"
    req = _dump_get(path)
    def _call():
        return BIRBankClient(doc.login_name).get_json(path)
    return _run(docname, _call, req)
