# src/fmatch/saas/api/v2/admin_manual.py
from fastapi import APIRouter, Depends, HTTPException, Request
from pydantic import BaseModel
from typing import Dict, Optional
from uuid import UUID
from sqlalchemy.ext.asyncio import AsyncSession

from ...db import get_session
from ...auth import get_current_account
from ...auth_security import require_admin
from ...model_defs.l2a_models import L2APolicy, L2ASuggestion
from sqlalchemy import select
from datetime import datetime
from .l2a import apply_suggestions  # Reuse existing apply pipeline
from ...services.salesforce_gateway import (
    SalesforceGateway,
    get_salesforce_gateway,
)

router = APIRouter(prefix="/api/v2/admin", tags=["admin"])


class ManualL2ALink(BaseModel):
    lead_id: str
    account_id: str
    apply_now: bool = False
    override_reason: Optional[str] = None
    evidence: Dict = {}


@router.post("/l2a/manual-link", dependencies=[Depends(require_admin)])
async def create_manual_link(
    body: ManualL2ALink,
    request: Request,
    db: AsyncSession = Depends(get_session),
    account_id: UUID = Depends(get_current_account),
    admin: str = Depends(require_admin),  # SECURITY FIX: Require admin role
):
    """
    Create a manual L2A link between a lead and account.
    REQUIRES: Admin role authentication
    """
    # Create a suggestion (status=pending, origin=manual) and optionally apply it
    # Reuse the existing /l2a/apply pipeline for auditability/undo.

    # 1) Load active L2A policy for this account
    pol_res = await db.execute(
        select(L2APolicy).where(
            L2APolicy.account_id == str(account_id), L2APolicy.status == "ACTIVE"
        )
    )
    policy = pol_res.scalar_one_or_none()
    if not policy:
        raise HTTPException(400, "No active L2A policy found for this account")

    # Determine writeback field
    writeback_field = policy.link_field_api_name or policy.lead_lookup_field
    if not writeback_field:
        raise HTTPException(400, "No Lead->Account writeback field configured")

    # 2) Determine reason_code (assign vs upgrade) by checking incumbent
    # Use gateway to read current value for correctness
    sf: SalesforceGateway = await get_salesforce_gateway(
        db=db, account_id=str(account_id)
    )
    try:
        lead = await sf.get_record("Lead", body.lead_id, fields=[writeback_field])
        incumbent = lead.get(writeback_field)
    except Exception:
        incumbent = None

    reason_code = "assign"
    incumbent_account_id = None
    if incumbent and incumbent != body.account_id:
        reason_code = "upgrade"
        incumbent_account_id = incumbent

    # 3) Create suggestion row
    suggestion = L2ASuggestion(
        policy_id=policy.id,
        lead_id=body.lead_id,
        account_id=body.account_id,
        score=None,
        tier=None,
        reasons=None,
        explanation=(body.override_reason or "manual"),
        status="pending",
        reason_code=reason_code,
        incumbent_account_id=incumbent_account_id,
        created_at=datetime.utcnow(),
    )
    db.add(suggestion)
    await db.flush()

    result = {
        "status": "ok",
        "mode": "applied" if body.apply_now else "queued",
        "linked": False,
        "suggestion_id": suggestion.id,
        "message": f"Queued manual link Lead {body.lead_id} -> Account {body.account_id}",
        "created_by": admin,
    }

    # 4) Optionally apply via standard pipeline for auditability
    if body.apply_now:
        try:
            apply_res = await apply_suggestions(
                suggestion_ids=[suggestion.id],
                db=db,
                account_id=str(account_id),
                user_id=str(admin),
                sf=sf,
            )
            result.update(
                {
                    "linked": True,
                    "apply_result": apply_res,
                }
            )
        except HTTPException as e:
            # Surface policy/writeback violations clearly
            raise e
        except Exception as e:
            raise HTTPException(500, f"Apply failed: {e}")

    await db.commit()
    return result


class ManualDedupePair(BaseModel):
    object_type: str
    record_a_id: str
    record_b_id: str
    apply_now: bool = False
    override_reason: Optional[str] = None
    evidence: Dict = {}


@router.post("/dedupe/manual-pair")
async def create_manual_pair(
    body: ManualDedupePair,
    request: Request,
    db: AsyncSession = Depends(get_session),
    account_id: UUID = Depends(get_current_account),
    admin: str = Depends(require_admin),  # SECURITY FIX: Require admin role
):
    """
    Create a manual dedupe pair for review or immediate merge.
    REQUIRES: Admin role authentication
    """
    # Create a 2-record cluster (origin=manual) and either return it for review
    # or immediately launch applyMerge (policy-driven).

    # TODO: Implement actual cluster creation
    # For now, return proper structure for frontend
    import uuid

    cluster_id = str(uuid.uuid4())

    return {
        "status": "ok",
        "cluster_id": cluster_id,
        "object_type": body.object_type,
        "mode": "applied" if body.apply_now else "queued",
        "queued": not body.apply_now,
        "message": f"{'Created cluster for immediate merge' if body.apply_now else 'Pair queued for review'}",
        "created_by": admin,  # Track who created this manual pair
    }
