"""
Purchase approval workflow and control endpoints.

Supports configurable maker-checker rules, work queues, and approval policy management.
"""
from fastapi import APIRouter, Depends, HTTPException, Query, Request
from sqlalchemy.orm import Session
from sqlalchemy import desc
from typing import Optional
from decimal import Decimal
from datetime import date, datetime

from app.core.database import get_db
from app.core.config import settings
from app.core.dependencies import get_current_user, get_current_company_id
from app.models.purchases import Purchase
from app.models.user import User
from app.models.branch import Branch

router = APIRouter(prefix="/purchase-approvals", tags=["purchases:approvals"])


def _get_policy():
    """Retrieve current approval policy from config."""
    mode = (settings.purchase_approval_mode or "single_operator").lower().strip()
    self_max = Decimal(str(settings.purchase_self_approve_max or 0))
    return {"mode": mode, "self_approve_max": float(self_max)}


@router.get("/policy")
async def get_approval_policy(db: Session = Depends(get_db)):
    """Get current organization approval policy (read-only from config)."""
    policy = _get_policy()
    return {
        "success": True,
        "data": {
            "mode": policy["mode"],
            "self_approve_max": policy["self_approve_max"],
            "description": (
                "Single Operator: Users can request and approve their own purchases (fastest path)."
                if policy["mode"] == "single_operator"
                else (
                    f"Segregated: Enforces maker-checker. Self-approval only if amount ≤ {policy['self_approve_max']}; "
                    "otherwise approver must differ from requester."
                )
            )
        },
        "message": "Approval policy retrieved"
    }


@router.get("/needs-approval")
async def list_purchases_needing_approval(
    skip: int = Query(0, ge=0),
    limit: int = Query(20, ge=1, le=100),
    db: Session = Depends(get_db),
    company_id: Optional[str] = Depends(get_current_company_id),
):
    """
    Work queue: list purchases awaiting approval (status pending/draft and not yet approved).

    Useful for segregated mode to show approvers their action items.
    """
    try:
        _q = db.query(Purchase).filter(
            Purchase.approved_by.is_(None),
            Purchase.status.in_(["pending", "draft", "ordered"])
        )
        if company_id:
            branch_ids_sq = db.query(Branch.id).filter(Branch.company_id == company_id)
            _q = _q.filter(Purchase.branch_id.in_(branch_ids_sq))
        query = _q.order_by(desc(Purchase.created_at))

        total = query.count()
        purchases = query.offset(skip).limit(limit).all()

        result = []
        for p in purchases:
            branch_name = None
            if p.branch_id:
                branch = db.query(Branch).filter(Branch.id == p.branch_id).first()
                branch_name = branch.name if branch else None

            creator_name = None
            if p.created_by:
                creator = db.query(User).filter(User.id == p.created_by).first()
                if creator:
                    parts = [x for x in [creator.first_name, creator.last_name] if x]
                    creator_name = " ".join(parts) if parts else creator.username

            result.append({
                "id": p.id,
                "reference": p.reference,
                "supplier_id": p.supplier_id,
                "supplier_name": p.supplier.name if p.supplier else None,
                "total_amount": float(p.total_amount or 0),
                "created_at": p.created_at.isoformat() if p.created_at else None,
                "created_by": p.created_by,
                "created_by_name": creator_name,
                "branch_id": p.branch_id,
                "branch_name": branch_name,
                "status": p.status,
                "days_pending": (date.today() - p.purchase_date.date() if p.purchase_date else 0)
            })

        return {
            "success": True,
            "data": result,
            "meta": {
                "total": total,
                "skip": skip,
                "limit": limit,
                "returned": len(result)
            },
            "message": f"Retrieved {len(result)} purchases awaiting approval"
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error fetching approval queue: {str(e)}")


@router.get("/needs-posting")
async def list_purchases_needing_posting(
    skip: int = Query(0, ge=0),
    limit: int = Query(20, ge=1, le=100),
    db: Session = Depends(get_db),
    company_id: Optional[str] = Depends(get_current_company_id),
):
    """
    Posting queue: list approved purchases awaiting GL posting (approved but posting_status not posted).
    """
    try:
        _q2 = db.query(Purchase).filter(
            Purchase.approved_by.isnot(None),
            (Purchase.posting_status.is_(None) | (Purchase.posting_status != "posted"))
        )
        if company_id:
            branch_ids_sq = db.query(Branch.id).filter(Branch.company_id == company_id)
            _q2 = _q2.filter(Purchase.branch_id.in_(branch_ids_sq))
        query = _q2.order_by(desc(Purchase.approved_at))

        total = query.count()
        purchases = query.offset(skip).limit(limit).all()

        result = []
        for p in purchases:
            branch_name = None
            if p.branch_id:
                branch = db.query(Branch).filter(Branch.id == p.branch_id).first()
                branch_name = branch.name if branch else None

            approver_name = None
            if p.approved_by:
                approver = db.query(User).filter(User.id == p.approved_by).first()
                if approver:
                    parts = [x for x in [approver.first_name, approver.last_name] if x]
                    approver_name = " ".join(parts) if parts else approver.username

            result.append({
                "id": p.id,
                "reference": p.reference,
                "supplier_name": p.supplier.name if p.supplier else None,
                "total_amount": float(p.total_amount or 0),
                "approved_at": p.approved_at.isoformat() if p.approved_at else None,
                "approved_by": p.approved_by,
                "approved_by_name": approver_name,
                "branch_id": p.branch_id,
                "branch_name": branch_name,
                "posting_status": p.posting_status or "pending",
                "status": p.status
            })

        return {
            "success": True,
            "data": result,
            "meta": {
                "total": total,
                "skip": skip,
                "limit": limit,
                "returned": len(result)
            },
            "message": f"Retrieved {len(result)} purchases awaiting posting"
        }
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error fetching posting queue: {str(e)}")


@router.post("/{purchase_id}/post")
async def post_purchase_to_ledger(
    purchase_id: str,
    payload: dict,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    Post an approved purchase to GL. Requires:
    - Purchase must be approved first
    - Poster will be the current user
    - Can optionally capture branch context

    Creates journal entries if not already posted.
    """
    try:
        # Use current user as the poster
        poster_id = current_user.id
        print(f"Posting purchase {purchase_id} to GL by user: {current_user.username} ({poster_id})")

        purchase = db.query(Purchase).filter(Purchase.id == purchase_id).first()
        if not purchase:
            raise HTTPException(status_code=404, detail="Purchase not found")

        if not purchase.approved_by:
            raise HTTPException(status_code=409, detail="Purchase must be approved before posting")

        if purchase.posting_status == "posted":
            raise HTTPException(status_code=400, detail="Purchase already posted to GL")

        # Mark as posting in progress
        purchase.posting_status = "posting"
        db.commit()

        try:
            from app.services.ifrs_accounting_service import IFRSAccountingService

            ifrs_service = IFRSAccountingService(db)
            journal_entries = ifrs_service.create_purchase_journal_entries(purchase, created_by_user_id=current_user.id)

            purchase.posting_status = "posted"
            purchase.posted_by = poster_id
            purchase.last_posted_date = datetime.utcnow()
            purchase.posted_from_branch_id = current_user.branch_id or purchase.branch_id

            db.commit()
            db.refresh(purchase)

            return {
                "success": True,
                "data": {
                    "purchase_id": purchase.id,
                    "posting_status": purchase.posting_status,
                    "posted_by": poster_id,
                    "posted_at": purchase.last_posted_date.isoformat() if purchase.last_posted_date else None,
                    "posted_from_branch_id": purchase.posted_from_branch_id,
                    "journal_entries_count": len(journal_entries) if journal_entries else 0
                },
                "message": "Purchase posted to GL successfully"
            }
        except Exception as je_error:
            purchase.posting_status = "error"
            db.commit()
            raise HTTPException(status_code=500, detail=f"Failed to create journal entries: {str(je_error)}")

    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=f"Error posting purchase: {str(e)}")
