from datetime import datetime, timedelta

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import func, select
from sqlalchemy.orm import Session

from app.db.session import get_db
from app.models.operations import Equipment, MaintenanceOrder, WorkCenter
from app.schemas.operations import (
    EquipmentCreate,
    EquipmentRead,
    MaintenanceOrderCreate,
    MaintenanceOrderRead,
)
from app.services.auth import require_authenticated_user
from app.services.operations import get_equipment_query, get_maintenance_orders_query, to_decimal
from app.services.system_permissions import ensure_employee_has_permission

router = APIRouter(dependencies=[Depends(require_authenticated_user)])


def _code_token(value: str | None, fallback: str, max_length: int = 12) -> str:
    token = "".join(ch for ch in str(value or "").upper() if ch.isalnum())
    return (token or fallback)[-max_length:]


def _next_doc_no(db: Session, model, column_name: str, prefix: str) -> str:
    column = getattr(model, column_name)
    count = db.scalar(select(func.count(model.id)).where(column.like(f"{prefix}-%"))) or 0
    return f"{prefix}-{count + 1:03d}"


def build_equipment_code(db: Session, work_center: WorkCenter, equipment_name: str | None) -> str:
    date_part = datetime.now().strftime("%Y%m%d")
    center_part = _code_token(work_center.center_code or work_center.center_name, f"WC{work_center.id:04d}", 10)
    equipment_part = _code_token(equipment_name, "EQ", 10)
    return _next_doc_no(db, Equipment, "equipment_code", f"EQ-NB-{date_part}-{center_part}-{equipment_part}")


def build_maintenance_order_no(db: Session, equipment: Equipment, maintenance_type: str | None) -> str:
    date_part = datetime.now().strftime("%Y%m%d")
    equipment_part = _code_token(equipment.equipment_code or equipment.equipment_name, f"EQ{equipment.id:04d}", 14)
    type_part = _code_token(maintenance_type, "MTN", 8)
    return _next_doc_no(db, MaintenanceOrder, "order_no", f"MTN-NB-{date_part}-{equipment_part}-{type_part}")


@router.get("/assets", response_model=list[EquipmentRead])
def list_equipment_assets(
    limit: int = Query(default=100, ge=1, le=500),
    db: Session = Depends(get_db),
) -> list[EquipmentRead]:
    rows = db.execute(get_equipment_query(limit=limit)).mappings().all()
    return [EquipmentRead.model_validate(dict(row)) for row in rows]


@router.post("/assets", response_model=EquipmentRead)
def create_equipment_asset(payload: EquipmentCreate, db: Session = Depends(get_db)) -> EquipmentRead:
    work_center = db.get(WorkCenter, payload.work_center_id)
    if not work_center:
        raise HTTPException(status_code=404, detail="工作中心不存在")

    equipment = Equipment(
        equipment_code=build_equipment_code(db, work_center, payload.equipment_name),
        equipment_name=payload.equipment_name,
        category_name=payload.category_name,
        work_center_id=payload.work_center_id,
        manufacturer=payload.manufacturer,
        model_no=payload.model_no,
        install_date=payload.install_date,
        rated_power_kw=to_decimal(payload.rated_power_kw, "0.01"),
        occupied_area_sqm=to_decimal(payload.occupied_area_sqm, "0.01"),
        maintenance_cycle_hours=to_decimal(payload.maintenance_cycle_hours, "0.01"),
        last_maintenance_at=None,
        next_maintenance_at=payload.next_maintenance_at,
        status=payload.status,
        remark=payload.remark,
    )
    db.add(equipment)
    db.commit()

    row = db.execute(get_equipment_query(limit=1).where(Equipment.id == equipment.id)).mappings().first()
    if not row:
        raise HTTPException(status_code=500, detail="设备创建后读取失败")
    return EquipmentRead.model_validate(dict(row))


@router.get("/maintenance-orders", response_model=list[MaintenanceOrderRead])
def list_maintenance_orders(
    limit: int = Query(default=100, ge=1, le=500),
    db: Session = Depends(get_db),
) -> list[MaintenanceOrderRead]:
    rows = db.execute(get_maintenance_orders_query(limit=limit)).mappings().all()
    return [MaintenanceOrderRead.model_validate(dict(row)) for row in rows]


@router.post("/maintenance-orders", response_model=MaintenanceOrderRead)
def create_maintenance_order(payload: MaintenanceOrderCreate, db: Session = Depends(get_db)) -> MaintenanceOrderRead:
    equipment = db.get(Equipment, payload.equipment_id)
    if not equipment:
        raise HTTPException(status_code=404, detail="设备不存在")
    ensure_employee_has_permission(
        db,
        payload.owner_employee_id,
        "MENU_EQUIPMENT_MANAGEMENT",
        "负责人",
        required=False,
    )

    order = MaintenanceOrder(
        order_no=build_maintenance_order_no(db, equipment, payload.maintenance_type),
        equipment_id=payload.equipment_id,
        plan_id=None,
        maintenance_type=payload.maintenance_type,
        start_time=payload.start_time or datetime.now(),
        end_time=payload.end_time,
        downtime_minutes=to_decimal(payload.downtime_minutes, "0.01"),
        owner_employee_id=payload.owner_employee_id,
        result_summary=payload.result_summary,
        cost_amount=to_decimal(payload.cost_amount, "0.01"),
        status=payload.status,
    )
    db.add(order)

    if payload.status == "COMPLETED" or payload.end_time:
        finished_time = payload.end_time or datetime.now()
        equipment.last_maintenance_at = finished_time
        if to_decimal(equipment.maintenance_cycle_hours, "0.01") > 0:
            equipment.next_maintenance_at = finished_time + timedelta(hours=float(equipment.maintenance_cycle_hours))
        db.add(equipment)

    db.commit()

    row = db.execute(get_maintenance_orders_query(limit=1).where(MaintenanceOrder.id == order.id)).mappings().first()
    if not row:
        raise HTTPException(status_code=500, detail="保养工单创建后读取失败")
    return MaintenanceOrderRead.model_validate(dict(row))
