from app.models.fingerspot_user import FingerspotUser
from app.utils.db import fetch_all, fetch_one, paginate
from fastapi import APIRouter, Depends, Request, UploadFile, File
from sqlalchemy.orm import Session, joinedload
from sqlalchemy import asc, desc, select
from pathlib import Path
import shutil
import uuid
import os
import csv
import io

from app.core.database import get_db
from app.core.response import send_response, send_error
from app.core.security import hash_password, verify_password
from app.models.user import User
from app.models.role import Role
from app.models.unit import Unit
from app.core.auth import get_current_user

router = APIRouter(prefix="/users", tags=["Users"])
UPLOAD_DIR = Path(os.environ["UPLOAD_PATH"])
UPLOAD_DIR.mkdir(parents=True, exist_ok=True)
DIR_MAP = {"avatar": "avatars", "sign": "signs"}


@router.post("")
async def store(
    request: Request,
    db: Session = Depends(get_db),
    user=Depends(get_current_user),
):
    body = await request.json()

    name = body.get("name")
    nip = body.get("nip")
    password = body.get("password")
    user_id = body.get("id")

    if not name or not nip:
        return send_error("Validation Error", {"name/nip": "required"})

    if user_id:
        user = db.query(User).filter(User.id == user_id).first()
        if not user:
            return send_error("User tidak ditemukan", status_code=404)
    else:
        if not password:
            return send_error("Password wajib diisi")

        user = User()

    for field in [
        "name",
        "nip",
        "pin",
        "role_id",
        "unit_id",
        "department_id",
        "phone_number",
        "is_active",
    ]:
        if field in body:
            setattr(user, field, body[field])

    if password:
        user.password = hash_password(password)
    db.add(user)
    db.commit()
    db.refresh(user)

    return send_response(user.to_dict(), "Sukses menyimpan user", 201)


@router.post("/bulk")
async def bulk_create_users(
    file: UploadFile = File(...),
    db: Session = Depends(get_db),
):
    content = await file.read()
    csv_file = io.StringIO(content.decode("utf-8-sig"))
    reader = csv.DictReader(csv_file)

    # 🔥 prefetch role
    roles = db.query(Role.slug, Role.id).all()
    role_map = {r.slug: r.id for r in roles}

    # 🔥 prefetch unit
    units = db.query(Unit.slug, Unit.id).all()
    unit_map = {u.slug: u.id for u in units}

    users = []
    errors = []

    for i, row in enumerate(reader, start=1):
        try:
            print(row)
            role_id = role_map[row["role_slug"]]
            unit_id = unit_map[row["unit_slug"]]

            user = User(
                nip=row["nip"],
                pin=row["pin"] or None,
                name=row["name"],
                is_active=1,
                role_id=role_id,
                unit_id=unit_id,
                password=hash_password(row["password"]),
            )

            users.append(user)

        except KeyError as e:
            errors.append({"row": i, "error": f"{e.args[0]} not found"})
    try:
        if users:
            db.bulk_save_objects(users)
            db.commit()
    except Exception as e:
        print(e)
    print(len(users), "userssssssss")
    return {"inserted": len(users), "errors": errors}


@router.get("")
def index(
    request: Request,
    db: Session = Depends(get_db),
    user=Depends(get_current_user),
):
    params = request.query_params
    per_page = int(params.get("itemsPerPage", 0))
    page = int(params.get("page", 1))
    sort_by = params.get("sortBy", "updated_at")
    sort_order = params.get("sortOrder", "desc")
    keyword = params.get("q")

    query = (
        select(
            User.id,
            User.nip,
            User.pin,
            User.name,
            User.is_active,
            User.updated_at,
            Role.id.label("role_id"),
            Role.name.label("role_name"),
            Unit.id.label("unit_id"),
            Unit.name.label("unit_name"),
        )
        .outerjoin(Role)
        .outerjoin(Unit)
    )

    if keyword:
        query = query.filter(User.name.like(f"%{keyword}%"))

    if per_page:
        rows = paginate(db, query, page, per_page, sort_by, sort_order)
    else:
        rows = fetch_all(db, query)
    return send_response(rows, "Daftar user")


@router.get("/profile")
def profile(
    current_user=Depends(get_current_user),
):
    user = current_user

    return send_response(
        {
            **user.to_dict(),
            "role": user.role.name if user.role else None,
            "role_slug": user.role.slug if user.role else None,
            "permissions": user.permissions(),
            "unit": user.unit.name,
            "unit_slug": user.unit.slug,
        },
        "User profile",
    )


@router.put("/profile/{image_type}")
async def upload_avatar(
    image_type: str,
    image: UploadFile = File(...),
    db: Session = Depends(get_db),
    current_user=Depends(get_current_user),
):
    allowed_ext = {".jpg", ".jpeg", ".png", ".webp"}
    ext = Path(image.filename).suffix.lower()

    if ext not in allowed_ext:
        return send_error("Invalid file type")

    # Generate filename unik
    filename = f"{uuid.uuid4()}{ext}"
    file_path = UPLOAD_DIR / DIR_MAP[image_type] / filename

    with file_path.open("wb") as buffer:
        shutil.copyfileobj(image.file, buffer)

    if current_user.image_path:
        old_file = UPLOAD_DIR / DIR_MAP[image_type] / current_user.image_path
        if old_file.exists():
            old_file.unlink()

    # Update DB
    if image_type == "avatar":
        current_user.image_path = filename
    if image_type == "sign":
        current_user.sign_path = filename
    db.commit()
    db.refresh(current_user)
    return {"message": "Avatar uploaded", "avatar_url": filename}


@router.put("/profile/password")
async def change_password(
    request: Request,
    db: Session = Depends(get_db),
    current_user=Depends(get_current_user),
):
    body = await request.json()
    new_password = body.get("new_password")
    old_password = body.get("old_password")
    if not (new_password and old_password):
        return send_error("Please provide password lama dan password baru")
    user = db.query(User).filter(User.id == current_user.id).first()
    if not user or not verify_password(old_password, user.password):
        return send_error(
            "Merubah password gagal",
            {"old_password": "Password salah"},
            401,
        )
    user.password = hash_password(new_password)
    db.commit()
    return send_response(user.to_dict(), "Berhasil merubah password")


@router.get("/daftar")
def daftar(
    db: Session = Depends(get_db),
    user=Depends(get_current_user),
):
    query = (
        select(
            User.id,
            User.name,
            User.nip,
            Unit.name.label("unit"),
            Role.name.label("role_name"),
        )
        .outerjoin(Role)
        .outerjoin(Unit)
        .filter(Role.slug != "admin", User.is_active == True)
        .order_by(User.name.asc())
    )
    rows = fetch_all(db, query)
    return send_response(rows, "Daftar user")


@router.get("/{user_id}")
def show(
    user_id: str,
    db: Session = Depends(get_db),
    user=Depends(get_current_user),
):
    stmt = (
        select(User)
        .options(
            joinedload(User.fingerspot),
        )
        .filter(User.id == user_id)
    )
    user = fetch_one(db, stmt)
    if not user:
        return send_error("User tidak ditemukan", status_code=404)
    user.pop("password")
    return send_response(user, "Detail user")


@router.delete("/{user_id}")
def destroy(
    user_id: str,
    db: Session = Depends(get_db),
    user=Depends(get_current_user),
):
    user = db.query(User).filter(User.id == user_id).first()

    if not user:
        return send_error("User tidak ditemukan", status_code=404)

    user.is_active = False
    db.commit()

    return send_response(user.to_dict(), "Berhasil menonaktifkan user")
