from __future__ import annotations
import uuid
from datetime import datetime, date
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from pydantic import BaseModel
from app.database import get_db
from app.models.employee import Employee, Attendance, Leave
from app.services.auth import get_current_user

router = APIRouter(prefix="/employees", tags=["employees"])


class EmployeeCreate(BaseModel):
    name: str
    phone: Optional[str] = None
    email: Optional[str] = None
    role: str
    department: Optional[str] = None
    salary: float = 0.0
    joining_date: Optional[date] = None
    is_active: bool = True

class EmployeeUpdate(BaseModel):
    name: Optional[str] = None
    phone: Optional[str] = None
    email: Optional[str] = None
    role: Optional[str] = None
    department: Optional[str] = None
    salary: Optional[float] = None
    joining_date: Optional[date] = None
    is_active: Optional[bool] = None

class EmployeeOut(BaseModel):
    id: str
    code: str
    name: str
    phone: Optional[str] = None
    email: Optional[str] = None
    role: str
    department: Optional[str] = None
    salary: float
    joining_date: Optional[date] = None
    is_active: bool
    created_at: datetime
    updated_at: datetime
    model_config = {"from_attributes": True}

class AttendanceCreate(BaseModel):
    employee_id: str
    date: date
    status: str = "present"
    check_in: Optional[str] = None
    check_out: Optional[str] = None
    hours_worked: float = 0.0
    notes: Optional[str] = None

class AttendanceOut(BaseModel):
    id: str
    employee_id: str
    date: date
    status: str
    check_in: Optional[str] = None
    check_out: Optional[str] = None
    hours_worked: float
    notes: Optional[str] = None
    created_at: datetime
    model_config = {"from_attributes": True}

class LeaveCreate(BaseModel):
    employee_id: str
    leave_type: str
    start_date: date
    end_date: date
    days: int = 1
    reason: Optional[str] = None

class LeaveUpdate(BaseModel):
    status: Optional[str] = None
    approved_by: Optional[str] = None

class LeaveOut(BaseModel):
    id: str
    employee_id: str
    leave_type: str
    start_date: date
    end_date: date
    days: int
    reason: Optional[str] = None
    status: str
    approved_by: Optional[str] = None
    created_at: datetime
    model_config = {"from_attributes": True}


def _generate_employee_code(db: Session) -> str:
    year = datetime.now().year
    last = db.query(Employee).filter(
        Employee.code.like(f"EMP-{year}-%")
    ).order_by(Employee.code.desc()).first()
    if last:
        seq = int(last.code.split("-")[-1]) + 1
    else:
        seq = 1
    return f"EMP-{year}-{seq:06d}"


@router.get("", response_model=list[EmployeeOut])
def list_employees(
    search: Optional[str] = None,
    department: Optional[str] = None,
    is_active: Optional[bool] = None,
    db: Session = Depends(get_db),
    _=Depends(get_current_user),
):
    q = db.query(Employee)
    if search:
        q = q.filter(Employee.name.ilike(f"%{search}%"))
    if department:
        q = q.filter(Employee.department == department)
    if is_active is not None:
        q = q.filter(Employee.is_active == is_active)
    return q.order_by(Employee.name).all()


@router.post("", response_model=EmployeeOut, status_code=201)
def create_employee(data: EmployeeCreate, db: Session = Depends(get_db), _=Depends(get_current_user)):
    obj = Employee(**data.model_dump(), code=_generate_employee_code(db))
    db.add(obj)
    db.commit()
    db.refresh(obj)
    return obj


@router.get("/attendance", response_model=list[AttendanceOut])
def list_attendance(
    employee_id: Optional[str] = None,
    from_date: Optional[date] = None,
    to_date: Optional[date] = None,
    db: Session = Depends(get_db),
    _=Depends(get_current_user),
):
    q = db.query(Attendance)
    if employee_id:
        q = q.filter(Attendance.employee_id == employee_id)
    if from_date:
        q = q.filter(Attendance.date >= from_date)
    if to_date:
        q = q.filter(Attendance.date <= to_date)
    return q.order_by(Attendance.date.desc()).all()


@router.post("/attendance", response_model=AttendanceOut, status_code=201)
def create_attendance(data: AttendanceCreate, db: Session = Depends(get_db), _=Depends(get_current_user)):
    emp = db.query(Employee).filter(Employee.id == data.employee_id).first()
    if not emp:
        raise HTTPException(status_code=404, detail="Employee not found")
    obj = Attendance(**data.model_dump())
    db.add(obj)
    db.commit()
    db.refresh(obj)
    return obj


@router.put("/attendance/{attendance_id}", response_model=AttendanceOut)
def update_attendance(attendance_id: str, data: AttendanceCreate, db: Session = Depends(get_db), _=Depends(get_current_user)):
    obj = db.query(Attendance).filter(Attendance.id == attendance_id).first()
    if not obj:
        raise HTTPException(status_code=404, detail="Attendance record not found")
    for k, v in data.model_dump().items():
        setattr(obj, k, v)
    db.commit()
    db.refresh(obj)
    return obj


@router.post("/attendance/bulk", response_model=list[AttendanceOut])
def bulk_upsert_attendance(records: list[AttendanceCreate], db: Session = Depends(get_db), _=Depends(get_current_user)):
    result = []
    for data in records:
        existing = db.query(Attendance).filter(
            Attendance.employee_id == data.employee_id,
            Attendance.date == data.date,
        ).first()
        if existing:
            for k, v in data.model_dump().items():
                setattr(existing, k, v)
            db.flush()
            result.append(existing)
        else:
            obj = Attendance(**data.model_dump())
            db.add(obj)
            db.flush()
            result.append(obj)
    db.commit()
    for r in result:
        db.refresh(r)
    return result


@router.delete("/attendance/{attendance_id}")
def delete_attendance(attendance_id: str, db: Session = Depends(get_db), _=Depends(get_current_user)):
    obj = db.query(Attendance).filter(Attendance.id == attendance_id).first()
    if not obj:
        raise HTTPException(status_code=404, detail="Attendance record not found")
    db.delete(obj)
    db.commit()
    return {"detail": "Attendance record deleted"}


@router.get("/leaves", response_model=list[LeaveOut])
def list_leaves(
    employee_id: Optional[str] = None,
    status: Optional[str] = None,
    db: Session = Depends(get_db),
    _=Depends(get_current_user),
):
    q = db.query(Leave)
    if employee_id:
        q = q.filter(Leave.employee_id == employee_id)
    if status:
        q = q.filter(Leave.status == status)
    return q.order_by(Leave.created_at.desc()).all()


@router.post("/leaves", response_model=LeaveOut, status_code=201)
def create_leave(data: LeaveCreate, db: Session = Depends(get_db), _=Depends(get_current_user)):
    emp = db.query(Employee).filter(Employee.id == data.employee_id).first()
    if not emp:
        raise HTTPException(status_code=404, detail="Employee not found")
    obj = Leave(**data.model_dump())
    db.add(obj)
    db.commit()
    db.refresh(obj)
    return obj


@router.get("/leaves/{leave_id}", response_model=LeaveOut)
def get_leave(leave_id: str, db: Session = Depends(get_db), _=Depends(get_current_user)):
    obj = db.query(Leave).filter(Leave.id == leave_id).first()
    if not obj:
        raise HTTPException(status_code=404, detail="Leave not found")
    return obj


@router.put("/leaves/{leave_id}/approve", response_model=LeaveOut)
@router.patch("/leaves/{leave_id}/approve", response_model=LeaveOut)
def approve_leave(leave_id: str, db: Session = Depends(get_db), current_user=Depends(get_current_user)):
    obj = db.query(Leave).filter(Leave.id == leave_id).first()
    if not obj:
        raise HTTPException(status_code=404, detail="Leave not found")
    obj.status = "approved"
    obj.approved_by = current_user.id
    db.commit()
    db.refresh(obj)
    return obj


@router.put("/leaves/{leave_id}/reject", response_model=LeaveOut)
@router.patch("/leaves/{leave_id}/reject", response_model=LeaveOut)
def reject_leave(leave_id: str, db: Session = Depends(get_db), current_user=Depends(get_current_user)):
    obj = db.query(Leave).filter(Leave.id == leave_id).first()
    if not obj:
        raise HTTPException(status_code=404, detail="Leave not found")
    obj.status = "rejected"
    obj.approved_by = current_user.id
    db.commit()
    db.refresh(obj)
    return obj


@router.get("/{employee_id}", response_model=EmployeeOut)
def get_employee(employee_id: str, db: Session = Depends(get_db), _=Depends(get_current_user)):
    obj = db.query(Employee).filter(Employee.id == employee_id).first()
    if not obj:
        raise HTTPException(status_code=404, detail="Employee not found")
    return obj


@router.put("/{employee_id}", response_model=EmployeeOut)
def update_employee(employee_id: str, data: EmployeeUpdate, db: Session = Depends(get_db), _=Depends(get_current_user)):
    obj = db.query(Employee).filter(Employee.id == employee_id).first()
    if not obj:
        raise HTTPException(status_code=404, detail="Employee not found")
    for k, v in data.model_dump(exclude_unset=True).items():
        setattr(obj, k, v)
    db.commit()
    db.refresh(obj)
    return obj


@router.delete("/{employee_id}")
def delete_employee(employee_id: str, db: Session = Depends(get_db), _=Depends(get_current_user)):
    obj = db.query(Employee).filter(Employee.id == employee_id).first()
    if not obj:
        raise HTTPException(status_code=404, detail="Employee not found")
    db.delete(obj)
    db.commit()
    return {"detail": "Employee deleted"}
