from __future__ import annotations

from datetime import datetime
from typing import Callable

from fastapi import FastAPI, File, HTTPException, UploadFile


def register_member_routes(
    app: FastAPI,
    *,
    get_conn,
    member_payload_cls,
    member_bulk_payload_cls,
    parse_as_of: Callable[[str | None], datetime | None],
    fetch_members: Callable[[], list[dict[str, object]]],
    fetch_members_as_of: Callable[[object, datetime], list[dict[str, object]]],
    build_member_compare_items: Callable[[list[dict[str, object]], list[dict[str, object]]], list[dict[str, object]]],
    serialize_member_payload: Callable[[object, int], tuple[object, ...]],
    sync_auth_users_from_members: Callable[[object], None],
    create_history_revision: Callable[[object, str, str], int],
    sync_member_versions: Callable[[object, list[int], str, int], None],
    sync_seat_assignment_versions: Callable[[object, list[int], str, int], None],
    replace_members: Callable[[list[object]], list[dict[str, object]]],
    parse_import_rows: Callable[[UploadFile, bytes], list[object]],
) -> None:
    @app.get("/api/members")
    def list_members(as_of: str | None = None) -> dict[str, list[dict[str, object]]]:
        parsed_as_of = parse_as_of(as_of)
        if parsed_as_of is None:
            return {"items": fetch_members()}
        with get_conn() as conn:
            with conn.cursor() as cur:
                return {"items": fetch_members_as_of(cur, parsed_as_of)}

    @app.get("/api/history/members/compare")
    def compare_members_history(from_date: str, to_date: str) -> dict[str, list[dict[str, object]]]:
        parsed_from = parse_as_of(from_date)
        parsed_to = parse_as_of(to_date)
        if parsed_from is None or parsed_to is None:
            raise HTTPException(status_code=400, detail="from_date and to_date are required.")
        with get_conn() as conn:
            with conn.cursor() as cur:
                from_items = fetch_members_as_of(cur, parsed_from)
                to_items = fetch_members_as_of(cur, parsed_to)
        return {"items": build_member_compare_items(from_items, to_items)}

    @app.post("/api/members")
    def create_member(payload: member_payload_cls) -> dict[str, object]:
        with get_conn() as conn:
            with conn.cursor() as cur:
                cur.execute("SELECT COALESCE(MAX(sort_order), -1) + 1 AS next_order FROM members")
                next_order = int(cur.fetchone()["next_order"])
                cur.execute(
                    """
                    INSERT INTO members (
                        name, employee_id, company, rank, role, department, grp, division, team, cell,
                        work_status, work_time, phone, email, seat_label, photo_url, sort_order
                    )
                    VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
                    RETURNING id, name, employee_id, company, rank, role, department, grp, division, team, cell,
                              work_status, work_time, phone, email, seat_label, photo_url,
                              sort_order, created_at, updated_at
                    """,
                    serialize_member_payload(payload, payload.sort_order if payload.sort_order is not None else next_order),
                )
                member = cur.fetchone()
                sync_auth_users_from_members(cur)
                revision_no = create_history_revision(cur, "member-create", f"Member created id={int(member['id'])}")
                sync_member_versions(cur, [int(member["id"])], "member-create", revision_no)
            conn.commit()
        return {"item": member}

    @app.put("/api/members/bulk-sync")
    def bulk_sync_members(payload: member_bulk_payload_cls) -> dict[str, list[dict[str, object]]]:
        return {"items": replace_members(payload.items)}

    @app.put("/api/members/{member_id}")
    def update_member(member_id: int, payload: member_payload_cls) -> dict[str, object]:
        with get_conn() as conn:
            with conn.cursor() as cur:
                cur.execute(
                    """
                    UPDATE members
                    SET name = %s,
                        employee_id = %s,
                        company = %s,
                        rank = %s,
                        role = %s,
                        department = %s,
                        grp = %s,
                        division = %s,
                        team = %s,
                        cell = %s,
                        work_status = %s,
                        work_time = %s,
                        phone = %s,
                        email = %s,
                        seat_label = %s,
                        photo_url = %s,
                        sort_order = COALESCE(%s, sort_order),
                        updated_at = NOW()
                    WHERE id = %s
                    RETURNING id, name, employee_id, company, rank, role, department, grp, division, team, cell,
                              work_status, work_time, phone, email, seat_label, photo_url,
                              sort_order, created_at, updated_at
                    """,
                    (*serialize_member_payload(payload, payload.sort_order or 0)[:-1], payload.sort_order, member_id),
                )
                member = cur.fetchone()
                if member is None:
                    raise HTTPException(status_code=404, detail="Member not found.")
                sync_auth_users_from_members(cur)
                revision_no = create_history_revision(cur, "member-update", f"Member updated id={member_id}")
                sync_member_versions(cur, [member_id], "member-update", revision_no)
                sync_seat_assignment_versions(cur, [member_id], "member-update", revision_no)
            conn.commit()
        return {"item": member}

    @app.delete("/api/members/{member_id}")
    def delete_member(member_id: int) -> dict[str, bool]:
        with get_conn() as conn:
            with conn.cursor() as cur:
                cur.execute("DELETE FROM members WHERE id = %s", (member_id,))
                deleted = cur.rowcount > 0
                if deleted:
                    sync_auth_users_from_members(cur)
                    revision_no = create_history_revision(cur, "member-delete", f"Member deleted id={member_id}")
                    sync_member_versions(cur, [member_id], "member-delete", revision_no)
                    sync_seat_assignment_versions(cur, [member_id], "member-delete", revision_no)
            conn.commit()
        if not deleted:
            raise HTTPException(status_code=404, detail="Member not found.")
        return {"ok": True}

    @app.post("/api/members/import")
    async def import_members(file: UploadFile = File(...)) -> dict[str, list[dict[str, object]]]:
        content = await file.read()
        items = parse_import_rows(file, content)
        return {"items": replace_members(items)}
