from __future__ import annotations

from datetime import datetime
from typing import Any, Dict, List, Optional

from sqlalchemy import select
from sqlalchemy.orm import Session

from db.models import ShopifyConnection
from settings import load_shopify_config
from shopify.admin_api import ShopifyAdminGraphQLClient


def upsert_connection(session: Session, payload: Dict[str, Any]) -> ShopifyConnection:
    shop_domain = str(payload.get("shop_domain") or "").strip()
    if not shop_domain:
        raise ValueError("shop_domain is required")
    shop_code = str(payload.get("shop_code") or "").strip() or shop_domain
    row = session.scalar(select(ShopifyConnection).where(ShopifyConnection.shop_code == shop_code))
    if row is None:
        row = ShopifyConnection(shop_code=shop_code, shop_domain=shop_domain)
        session.add(row)
    row.shop_domain = shop_domain
    for field in ("api_version", "admin_access_token", "client_id", "client_secret", "status", "environment", "notes"):
        value = payload.get(field)
        if value is not None:
            setattr(row, field, str(value).strip())
    session.flush()
    return row


def update_connection(session: Session, connection_id: int, payload: Dict[str, Any]) -> ShopifyConnection:
    row = session.get(ShopifyConnection, connection_id)
    if row is None:
        raise LookupError("Connection not found")
    allowed = {
        "shop_domain",
        "api_version",
        "admin_access_token",
        "client_id",
        "client_secret",
        "status",
        "environment",
        "notes",
    }
    for field, value in payload.items():
        if field in allowed and value is not None:
            setattr(row, field, str(value).strip())
    session.flush()
    return row


def list_connections(session: Session) -> List[Dict[str, Any]]:
    rows = session.scalars(select(ShopifyConnection).order_by(ShopifyConnection.id)).all()
    return [connection_summary(row) for row in rows]


def connection_summary(row: ShopifyConnection) -> Dict[str, Any]:
    """Safe representation for API responses — never returns secrets."""
    return {
        "id": row.id,
        "shop_code": row.shop_code,
        "shop_domain": row.shop_domain,
        "api_version": row.api_version,
        "status": row.status,
        "environment": row.environment,
        "has_access_token": bool(row.admin_access_token),
        "has_client_credentials": bool(row.client_id and row.client_secret),
        "notes": row.notes or "",
        "last_verified_at": row.last_verified_at.isoformat() if row.last_verified_at else None,
        "last_error": row.last_error,
    }


def get_active_connection(session: Session, *, shop_code: Optional[str] = None) -> Optional[ShopifyConnection]:
    stmt = select(ShopifyConnection).where(ShopifyConnection.status == "active").order_by(ShopifyConnection.id)
    if shop_code:
        stmt = stmt.where(ShopifyConnection.shop_code == shop_code)
    return session.scalars(stmt).first()


def shopify_connection_credentials(connection: ShopifyConnection) -> Dict[str, Any]:
    """Snapshot credentials while the ORM row is still bound to a session."""
    return {
        "shop_domain": connection.shop_domain,
        "admin_access_token": connection.admin_access_token or None,
        "client_id": connection.client_id or None,
        "client_secret": connection.client_secret or None,
        "api_version": connection.api_version,
    }


def build_client(connection: Optional[ShopifyConnection]) -> ShopifyAdminGraphQLClient:
    """Build a GraphQL client from a DB connection row, falling back to ENV config."""
    if connection is not None:
        creds = shopify_connection_credentials(connection)
        return ShopifyAdminGraphQLClient(
            shop_domain=creds["shop_domain"],
            admin_access_token=creds["admin_access_token"],
            client_id=creds["client_id"],
            client_secret=creds["client_secret"],
            api_version=creds["api_version"],
        )
    cfg = load_shopify_config()
    return ShopifyAdminGraphQLClient(
        shop_domain=cfg.shop_domain,
        admin_access_token=cfg.admin_access_token or None,
        client_id=cfg.client_id or None,
        client_secret=cfg.client_secret or None,
        api_version=cfg.api_version,
    )


def verify_connection(session: Session, connection_id: int) -> Dict[str, Any]:
    row = session.get(ShopifyConnection, connection_id)
    if row is None:
        raise LookupError("Connection not found")
    try:
        client = build_client(row)
        data = client.graphql("{ shop { name currencyCode } }")
        shop = data.get("shop") or {}
        row.last_verified_at = datetime.utcnow()
        row.last_error = None
        return {"verified": True, "shop_name": shop.get("name"), "currency": shop.get("currencyCode")}
    except Exception as exc:
        row.last_error = str(exc)
        return {"verified": False, "error": str(exc)}
