from __future__ import annotations

import logging
import math
from datetime import datetime, timezone
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, Query, Request, status
from sqlalchemy.orm import Session

from src.apps.auth.utils.auth import get_current_superuser
from src.apps.users.models.user import User
from src.core.database import get_session

from src.apps.pricing_control.schemas.pricing_schemas import (
    BulkAssignRequest,
    InterchangeRateCreate,
    InterchangeRateUpdate,
    MerchantPricingAssignRequest,
    PricingTemplateCreate,
    PricingTemplateUpdate,
)
import src.apps.pricing_control.crud as crud

logger = logging.getLogger(__name__)

router = APIRouter()


def _get_ip(request: Request) -> str:
    forwarded = request.headers.get("X-Forwarded-For")
    if forwarded:
        return forwarded.split(",")[-1].strip()
    return request.client.host if request.client else "unknown"


def _audit(db, user_id, action, target_type, target_id, metadata=None, ip=None):
    from src.apps.admin.models.admin_audit_log import AdminAuditLog
    AdminAuditLog.log(
        db,
        admin_user_id=user_id,
        action=action,
        target_type=target_type,
        target_id=target_id,
        metadata=metadata,
        ip_address=ip,
    )


# ─── Pricing Templates ────────────────────────────────────────────────────────

@router.get("/pricing/templates", tags=["ADMIN_PRICING"])
async def list_pricing_templates(
    page: int = Query(1, ge=1),
    per_page: int = Query(20, ge=1, le=100),
    pricing_type: Optional[str] = Query(None),
    is_active: Optional[bool] = Query(None),
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    items, total = crud.get_templates(db, page=page, per_page=per_page, pricing_type=pricing_type, is_active=is_active)
    return {
        "data": [_template_to_dict(t) for t in items],
        "total": total,
        "page": page,
        "per_page": per_page,
        "pages": math.ceil(total / per_page) if per_page else 1,
    }


@router.post("/pricing/templates", tags=["ADMIN_PRICING"], status_code=status.HTTP_201_CREATED)
async def create_pricing_template(
    request: Request,
    body: PricingTemplateCreate,
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    template = crud.create_template(db, data=body, created_by_user_id=current_user.id)
    _audit(db, current_user.id, "pricing_template.created", "pricing_template", template.id,
           {"name": template.name, "pricing_type": template.pricing_type}, _get_ip(request))
    db.commit()
    return _template_to_dict(template)


@router.get("/pricing/templates/{template_id}", tags=["ADMIN_PRICING"])
async def get_pricing_template(
    template_id: int,
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    template = crud.get_template(db, template_id)
    if not template:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Pricing template not found")
    return _template_to_dict(template)


@router.patch("/pricing/templates/{template_id}", tags=["ADMIN_PRICING"])
async def update_pricing_template(
    template_id: int,
    request: Request,
    body: PricingTemplateUpdate,
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    new_template = crud.update_template(db, template_id=template_id, data=body, updated_by_user_id=current_user.id)
    _audit(db, current_user.id, "pricing_template.updated", "pricing_template", new_template.id,
           {"name": new_template.name, "parent_template_id": new_template.parent_template_id}, _get_ip(request))
    db.commit()
    return _template_to_dict(new_template)


@router.delete("/pricing/templates/{template_id}", tags=["ADMIN_PRICING"], status_code=status.HTTP_204_NO_CONTENT)
async def delete_pricing_template(
    template_id: int,
    request: Request,
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    crud.soft_delete_template(db, template_id)
    _audit(db, current_user.id, "pricing_template.deleted", "pricing_template", template_id, ip=_get_ip(request))
    db.commit()


@router.post("/pricing/templates/{template_id}/clone", tags=["ADMIN_PRICING"], status_code=status.HTTP_201_CREATED)
async def clone_pricing_template(
    template_id: int,
    request: Request,
    body: dict,
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    new_name = body.get("name")
    if not new_name:
        raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail="name is required")
    cloned = crud.clone_template(db, template_id=template_id, new_name=new_name, created_by_user_id=current_user.id)
    _audit(db, current_user.id, "pricing_template.cloned", "pricing_template", cloned.id,
           {"cloned_from": template_id, "name": cloned.name}, _get_ip(request))
    db.commit()
    return _template_to_dict(cloned)


@router.get("/pricing/templates/{template_id}/history", tags=["ADMIN_PRICING"])
async def get_template_history(
    template_id: int,
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    versions = crud.get_template_history(db, template_id)
    return {"versions": [_template_to_dict(v) for v in versions], "total": len(versions)}


@router.post("/pricing/templates/{template_id}/assign", tags=["ADMIN_PRICING"], status_code=status.HTTP_201_CREATED)
async def bulk_assign_template(
    template_id: int,
    request: Request,
    body: BulkAssignRequest,
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    # TODO: agent scope check — verify_agent_merchant_scope (HWADM-001)
    assignments = crud.assign_template_to_merchants(
        db,
        template_id=template_id,
        merchant_ids=body.merchant_ids,
        effective_date=body.effective_date,
        assigned_by_user_id=current_user.id,
        notes=body.notes,
    )
    for a in assignments:
        _audit(db, current_user.id, "pricing_template.assigned", "merchant", a.merchant_id,
               {"template_id": template_id, "effective_date": a.effective_date.isoformat()}, _get_ip(request))
    db.commit()
    return {"assigned": len(assignments), "merchant_ids": [a.merchant_id for a in assignments]}


# ─── Interchange Rates ────────────────────────────────────────────────────────

@router.get("/pricing/interchange-rates", tags=["ADMIN_PRICING"])
async def list_interchange_rates(
    page: int = Query(1, ge=1),
    per_page: int = Query(50, ge=1, le=200),
    card_network: Optional[str] = Query(None),
    transaction_type: Optional[str] = Query(None),
    is_active: Optional[bool] = Query(None),
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    items, total = crud.get_interchange_rates(
        db, page=page, per_page=per_page,
        card_network=card_network, transaction_type=transaction_type, is_active=is_active,
    )
    return {
        "data": [_interchange_to_dict(r) for r in items],
        "total": total,
        "page": page,
        "per_page": per_page,
    }


@router.post("/pricing/interchange-rates", tags=["ADMIN_PRICING"], status_code=status.HTTP_201_CREATED)
async def create_interchange_rate_endpoint(
    request: Request,
    body: InterchangeRateCreate,
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    rate = crud.create_interchange_rate(db, data=body, created_by=current_user.id)
    _audit(db, current_user.id, "interchange_rate.created", "interchange_rate", rate.id,
           {"card_network": rate.card_network, "transaction_type": rate.transaction_type}, _get_ip(request))
    db.commit()
    return _interchange_to_dict(rate)


@router.patch("/pricing/interchange-rates/{rate_id}", tags=["ADMIN_PRICING"])
async def update_interchange_rate_endpoint(
    rate_id: int,
    request: Request,
    body: InterchangeRateUpdate,
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    rate = crud.update_interchange_rate(db, rate_id=rate_id, data=body)
    _audit(db, current_user.id, "interchange_rate.updated", "interchange_rate", rate.id, ip=_get_ip(request))
    db.commit()
    return _interchange_to_dict(rate)


@router.delete("/pricing/interchange-rates/{rate_id}", tags=["ADMIN_PRICING"], status_code=status.HTTP_204_NO_CONTENT)
async def delete_interchange_rate_endpoint(
    rate_id: int,
    request: Request,
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    crud.deactivate_interchange_rate(db, rate_id=rate_id)
    _audit(db, current_user.id, "interchange_rate.deleted", "interchange_rate", rate_id, ip=_get_ip(request))
    db.commit()


# ─── Merchant Pricing ─────────────────────────────────────────────────────────

@router.get("/merchants/{merchant_id}/pricing", tags=["ADMIN_PRICING"])
async def get_merchant_pricing(
    merchant_id: int,
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    active = crud.get_active_assignment(db, merchant_id)
    history = crud.get_merchant_assignments(db, merchant_id)
    return {
        "merchant_id": merchant_id,
        "active_assignment": _assignment_to_dict(active) if active else None,
        "history": [_assignment_to_dict(a) for a in history],
    }


@router.post("/merchants/{merchant_id}/pricing", tags=["ADMIN_PRICING"], status_code=status.HTTP_201_CREATED)
async def assign_pricing_to_merchant(
    merchant_id: int,
    request: Request,
    body: MerchantPricingAssignRequest,
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    # TODO: agent scope check — verify_agent_merchant_scope (HWADM-001)
    assignments = crud.assign_template_to_merchants(
        db,
        template_id=body.template_id,
        merchant_ids=[merchant_id],
        effective_date=body.effective_date,
        assigned_by_user_id=current_user.id,
        notes=body.notes,
    )
    a = assignments[0]
    _audit(db, current_user.id, "pricing_template.assigned", "merchant", merchant_id,
           {"template_id": body.template_id, "effective_date": body.effective_date.isoformat()}, _get_ip(request))
    db.commit()
    return _assignment_to_dict(a)


@router.get("/merchants/{merchant_id}/billing-records", tags=["ADMIN_PRICING"])
async def get_merchant_billing_records(
    merchant_id: int,
    page: int = Query(1, ge=1),
    per_page: int = Query(20, ge=1, le=100),
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    items, total = crud.get_billing_records(db, merchant_id=merchant_id, page=page, per_page=per_page)
    return {
        "data": [_billing_record_to_dict(r) for r in items],
        "total": total,
        "page": page,
        "per_page": per_page,
        "pages": math.ceil(total / per_page) if per_page else 1,
    }


@router.get("/merchants/{merchant_id}/billing-method", tags=["ADMIN_PRICING"])
async def get_merchant_billing_method(
    merchant_id: int,
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    method = crud.get_billing_method(db, merchant_id)
    if not method:
        return {"merchant_id": merchant_id, "billing_method": None}
    return {
        "merchant_id": merchant_id,
        "billing_method": {
            "id": method.id,
            "card_type": method.card_type,
            "masked_card": method.masked_card,
            "billing_name": method.billing_name,
            "is_active": method.is_active,
            "created_at": method.created_at.isoformat() if method.created_at else None,
        },
    }


# ─── Pricing Summary Report ───────────────────────────────────────────────────

@router.get("/reports/pricing-summary", tags=["ADMIN_PRICING"])
async def get_pricing_summary(
    page: int = Query(1, ge=1),
    per_page: int = Query(20, ge=1, le=100),
    date_from: Optional[datetime] = Query(None),
    date_to: Optional[datetime] = Query(None),
    merchant_id: Optional[int] = Query(None),
    pricing_type: Optional[str] = Query(None),
    db: Session = Depends(get_session),
    current_user: User = Depends(get_current_superuser),
):
    items, total = crud.get_pricing_summary(
        db, page=page, per_page=per_page,
        date_from=date_from, date_to=date_to,
        merchant_id=merchant_id, pricing_type=pricing_type,
    )
    return {
        "data": items,
        "total": total,
        "page": page,
        "per_page": per_page,
        "pages": math.ceil(total / per_page) if per_page else 1,
    }


# ─── Serializers ─────────────────────────────────────────────────────────────

def _template_to_dict(t) -> dict:
    return {
        "id": t.id,
        "name": t.name,
        "description": t.description,
        "pricing_type": t.pricing_type,
        "billing_cycle": t.billing_cycle,
        "monthly_fee_cents": t.monthly_fee_cents,
        "setup_fee_cents": t.setup_fee_cents,
        "is_active": t.is_active,
        "parent_template_id": t.parent_template_id,
        "created_by_user_id": t.created_by_user_id,
        "created_at": t.created_at.isoformat() if t.created_at else None,
        "updated_at": t.updated_at.isoformat() if t.updated_at else None,
        "rates": [_rate_to_dict(r) for r in (t.rates or [])],
    }


def _rate_to_dict(r) -> dict:
    return {
        "id": r.id,
        "template_id": r.template_id,
        "transaction_type": r.transaction_type,
        "rate_percentage": r.rate_percentage,
        "fixed_fee_cents": r.fixed_fee_cents,
        "tier_name": r.tier_name,
        "interchange_basis_points": r.interchange_basis_points,
        "markup_basis_points": r.markup_basis_points,
    }


def _assignment_to_dict(a) -> dict:
    return {
        "id": a.id,
        "merchant_id": a.merchant_id,
        "template_id": a.template_id,
        "template_name": a.template.name if a.template else None,
        "pricing_type": a.template.pricing_type if a.template else None,
        "effective_date": a.effective_date.isoformat() if a.effective_date else None,
        "is_active": a.is_active,
        "assigned_by_user_id": a.assigned_by_user_id,
        "notes": a.notes,
        "created_at": a.created_at.isoformat() if a.created_at else None,
    }


def _billing_record_to_dict(r) -> dict:
    return {
        "id": r.id,
        "merchant_id": r.merchant_id,
        "template_id": r.template_id,
        "period_start": r.period_start.isoformat() if r.period_start else None,
        "period_end": r.period_end.isoformat() if r.period_end else None,
        "total_volume_cents": r.total_volume_cents,
        "total_platform_fee_cents": r.total_platform_fee_cents,
        "monthly_fee_cents": r.monthly_fee_cents,
        "total_due_cents": r.total_due_cents,
        "status": r.status,
        "charge_txn_id": r.charge_txn_id,
        "retry_count": r.retry_count,
        "last_error": r.last_error,
        "created_at": r.created_at.isoformat() if r.created_at else None,
    }


def _interchange_to_dict(r) -> dict:
    return {
        "id": r.id,
        "card_network": r.card_network,
        "card_type": r.card_type,
        "transaction_type": r.transaction_type,
        "rate_percentage": r.rate_percentage,
        "fixed_fee_cents": r.fixed_fee_cents,
        "description": r.description,
        "effective_from": r.effective_from.isoformat() if r.effective_from else None,
        "effective_to": r.effective_to.isoformat() if r.effective_to else None,
        "is_active": r.is_active,
        "created_at": r.created_at.isoformat() if r.created_at else None,
    }
