from app.core.response import send_response
from app.models.fingerspot_user import FingerspotUser
from app.models.presensi_fingerspot import PresensiFingerspot, PresensiFingerspotLog
from sqlalchemy import select, func, and_, asc
from sqlalchemy.dialects.mysql import insert
from sqlalchemy.orm import Session, aliased
from typing import Any, Dict
import asyncio
import httpx
import logging
import time


FINGERSPOT_BASE_URL = "https://developer.fingerspot.io/api/"
CLOUD_ID = "C2636CF4DB241F31"
BEARER_TOKEN = "4GS4QDC1UHTOQRT7"

headers = {"Authorization": f"Bearer {BEARER_TOKEN}"}


async def fetch_scan_log(
    date: str,
) -> Dict[str, Any]:
    payload = {
        "trans_id": int(time.time()),
        "cloud_id": CLOUD_ID,
        "start_date": date,
        "end_date": date,
    }
    retries = 3
    timeout = 30
    delay = 5
    last_error = None

    for attempt in range(1, retries + 1):
        try:
            async with httpx.AsyncClient(timeout=timeout) as client:
                resp = await client.post(
                    FINGERSPOT_BASE_URL + "get_attlog", headers=headers, json=payload
                )

            resp.raise_for_status()
            data = resp.json()
            # validasi response structure
            if not data.get("success"):
                raise ValueError("API success=false")

            return data

        except Exception as e:
            last_error = e
            print(f"[retry {attempt}/{retries}] failed:", e)

            if attempt < retries:
                await asyncio.sleep(delay)

    raise RuntimeError(f"API failed after {retries} retries") from last_error


def save_presensi_from_response(resp: dict, db: Session, date: str):
    status = "success" if resp.get("success") else "failed"
    trans_id = resp["trans_id"]
    rows = resp.get("data", [])
    inserted = len(rows)
    try:
        # ✅ simpan log transaksi
        rows = [
            {"pin": r["pin"], "scan_date": r["scan_date"]} for r in rows if r.get("pin")
        ]
        log = PresensiFingerspotLog(trans_id=trans_id, status=status, date=date)
        db.merge(log)
        if rows:
            stmt = insert(PresensiFingerspot).values(rows)
            stmt = stmt.on_duplicate_key_update(updated_at=func.now())
            db.execute(stmt)

        db.commit()

    except Exception as e:
        print(e)
        db.rollback()
        raise

    return {"inserted": inserted, "trans_id": trans_id}


async def sync_users():
    async with httpx.AsyncClient() as client:
        resp = await client.post(
            FINGERSPOT_BASE_URL + "get_all_pin",
            headers=headers,
            json={
                "trans_id": int(time.time()),
                "cloud_id": CLOUD_ID,
            },
        )

    return resp


async def handle_userid_list(payload: dict):
    pins = payload["data"]["pin_arr"]
    trans_id = payload["trans_id"]

    async with httpx.AsyncClient() as client:
        for pin in pins:
            await client.post(
                FINGERSPOT_BASE_URL + "get_userinfo",
                headers=headers,
                json={
                    "trans_id": trans_id,
                    "cloud_id": CLOUD_ID,
                    "pin": pin,
                },
            )

    return send_response(None, "Processing user list")


async def handle_userinfo(payload: dict, db: Session):
    user_data = payload["data"]

    obj = (
        db.query(FingerspotUser).filter(FingerspotUser.pin == user_data["pin"]).first()
    )

    if obj:
        obj.name = user_data["name"]
    else:
        obj = FingerspotUser(
            pin=user_data["pin"],
            name=user_data["name"],
        )
        db.add(obj)

    db.commit()

    logging.info("User info saved", extra=user_data)
    return send_response(None, "User info processed successfully")


async def handle_attlog(payload: dict, db: Session):
    log_data = payload["data"]
    log_data = {"scan_date": log_data["scan"], "pin": log_data["pin"]}
    stmt = insert(PresensiFingerspot).values([log_data])
    stmt = stmt.on_duplicate_key_update(updated_at=func.now())
    log = PresensiFingerspotLog(trans_id=trans_id, status=status, date=date)
    db.merge(log)
    db.execute(stmt)
    db.commit()
    logging.info("Log info saved", extra=log_data)
    return send_response(None, "Log info processed successfully")
