from __future__ import annotations

from datetime import date
from uuid import uuid4

from sqlalchemy.orm import Session

from ..core.timezone import now_shanghai
from ..database.orm import AttendanceRecordORM, AttendanceSyncJobORM, EmployeeORM, SalaryPreviewORM


class RealtimeAttendanceRepository:
    """实时考勤仓库：封装同步批次、考勤记录和薪资预估的数据库读写。"""

    def __init__(self, session: Session):
        self.session = session

    def list_active_employees(self) -> list[EmployeeORM]:
        return (
            self.session.query(EmployeeORM)
            .filter(EmployeeORM.employment_status == "active")
            .order_by(EmployeeORM.id.asc())
            .all()
        )

    def list_active_employees_with_dingtalk(self) -> list[EmployeeORM]:
        return (
            self.session.query(EmployeeORM)
            .filter(EmployeeORM.employment_status == "active")
            .filter(EmployeeORM.dingtalk_user_id != "")
            .order_by(EmployeeORM.id.asc())
            .all()
        )

    def create_sync_job(
        self,
        *,
        source_type: str,
        sync_mode: str,
        attendance_date: date,
        salary_month: str,
        start_date: date,
        end_date: date,
        created_by: str,
    ) -> AttendanceSyncJobORM:
        job = AttendanceSyncJobORM(
            id=uuid4().hex,
            source_type=source_type,
            sync_mode=sync_mode,
            attendance_date=attendance_date,
            salary_month=salary_month,
            start_date=start_date,
            end_date=end_date,
            status="running",
            created_by=created_by,
        )
        self.session.add(job)
        self.session.commit()
        self.session.refresh(job)
        return job

    def mark_sync_completed(
        self,
        job_id: str,
        *,
        employee_count: int,
        record_count: int,
    ) -> AttendanceSyncJobORM:
        job = self.require_sync_job(job_id)
        job.status = "completed"
        job.employee_count = employee_count
        job.record_count = record_count
        job.error_message = ""
        job.updated_at = now_shanghai()
        self.session.commit()
        self.session.refresh(job)
        return job

    def mark_sync_failed(self, job_id: str, error_message: str) -> AttendanceSyncJobORM:
        job = self.require_sync_job(job_id)
        job.status = "failed"
        job.error_message = error_message
        job.updated_at = now_shanghai()
        self.session.commit()
        self.session.refresh(job)
        return job

    def require_sync_job(self, job_id: str) -> AttendanceSyncJobORM:
        job = self.session.query(AttendanceSyncJobORM).filter(AttendanceSyncJobORM.id == job_id).one_or_none()
        if job is None:
            raise ValueError("考勤同步任务不存在")
        return job

    def latest_completed_job(self, attendance_date: date) -> AttendanceSyncJobORM | None:
        return (
            self.session.query(AttendanceSyncJobORM)
            .filter(AttendanceSyncJobORM.attendance_date == attendance_date)
            .filter(AttendanceSyncJobORM.status == "completed")
            .order_by(AttendanceSyncJobORM.updated_at.desc(), AttendanceSyncJobORM.created_at.desc())
            .first()
        )

    def replace_attendance_records(
        self,
        *,
        source_type: str,
        start_date: date,
        end_date: date,
        employee_ids: list[int],
        rows: list[AttendanceRecordORM],
    ) -> None:
        if employee_ids:
            (
                self.session.query(AttendanceRecordORM)
                .filter(AttendanceRecordORM.source_type == source_type)
                .filter(AttendanceRecordORM.employee_id.in_(employee_ids))
                .filter(AttendanceRecordORM.work_date >= start_date)
                .filter(AttendanceRecordORM.work_date <= end_date)
                .delete(synchronize_session=False)
            )
        if rows:
            self.session.add_all(rows)
        self.session.commit()

    def replace_salary_previews(self, sync_job_id: str, rows: list[SalaryPreviewORM]) -> None:
        self.session.query(SalaryPreviewORM).filter(SalaryPreviewORM.sync_job_id == sync_job_id).delete(
            synchronize_session=False
        )
        if rows:
            self.session.add_all(rows)
        self.session.commit()

    def list_today_records(self, attendance_date: date) -> list[AttendanceRecordORM]:
        return (
            self.session.query(AttendanceRecordORM)
            .filter(AttendanceRecordORM.work_date == attendance_date)
            .filter(AttendanceRecordORM.source_type == "dingtalk")
            .order_by(AttendanceRecordORM.employee_name.asc(), AttendanceRecordORM.id.asc())
            .all()
        )

    def list_salary_previews(self, salary_month: str) -> list[SalaryPreviewORM]:
        return (
            self.session.query(SalaryPreviewORM)
            .filter(SalaryPreviewORM.salary_month == salary_month)
            .order_by(SalaryPreviewORM.updated_at.desc(), SalaryPreviewORM.id.desc())
            .all()
        )
