#!/usr/bin/env python3
"""Generate healthcare phases 13.2-13.7 implementation files."""
from __future__ import annotations

import textwrap
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
FILES: dict[str, str] = {}


def add(path: str, content: str) -> None:
    FILES[path] = textwrap.dedent(content).lstrip() + "\n"


# =============================================================================
# Phase 13.2 — Doctor Panel
# =============================================================================

add(
    "app/schemas/doctor_panel.py",
    '''\
    """Doctor panel DTOs — Phase 13.2."""
    from __future__ import annotations
    from datetime import datetime
    from uuid import UUID
    from pydantic import BaseModel, ConfigDict, Field
    from app.models.types import VisitSessionStatus
    from app.schemas.common import ORMBase
    from app.schemas.appointments import AppointmentRead

    _FORBID = ConfigDict(extra="forbid")

    class VisitSessionCreate(BaseModel):
        model_config = _FORBID
        clinic_id: UUID
        doctor_id: UUID
        patient_id: UUID
        appointment_id: UUID
        code: str = Field(max_length=50)
        queue_position: int = Field(default=100, ge=1, le=10000)
        metadata_json: dict | None = None

    class VisitSessionActionRequest(BaseModel):
        model_config = _FORBID
        version: int = Field(ge=1)
        reason: str | None = Field(default=None, max_length=500)

    class VisitSessionRead(ORMBase):
        id: UUID
        tenant_id: UUID
        clinic_id: UUID
        doctor_id: UUID
        patient_id: UUID
        appointment_id: UUID
        code: str
        status: VisitSessionStatus
        queue_position: int
        started_at: datetime | None
        finished_at: datetime | None
        metadata_json: dict | None
        version: int
        is_deleted: bool
        created_at: datetime
        updated_at: datetime

    class VisitNoteCreate(BaseModel):
        model_config = _FORBID
        visit_session_id: UUID
        doctor_id: UUID
        code: str = Field(max_length=50)
        title: str = Field(max_length=255)
        body: str | None = None
        storage_file_ref: str | None = Field(default=None, max_length=255)
        metadata_json: dict | None = None

    class VisitNoteUpdate(BaseModel):
        model_config = _FORBID
        title: str | None = Field(default=None, max_length=255)
        body: str | None = None
        storage_file_ref: str | None = Field(default=None, max_length=255)
        version: int = Field(ge=1)
        metadata_json: dict | None = None

    class VisitNoteRead(ORMBase):
        id: UUID
        tenant_id: UUID
        visit_session_id: UUID
        doctor_id: UUID
        code: str
        title: str
        body: str | None
        storage_file_ref: str | None
        metadata_json: dict | None
        version: int
        is_deleted: bool
        created_at: datetime
        updated_at: datetime

    class DoctorDashboardRead(BaseModel):
        doctor_id: UUID
        queued_count: int
        in_progress_count: int
        completed_today_count: int
        upcoming_appointments: list[AppointmentRead]

    class DoctorQueueRead(BaseModel):
        doctor_id: UUID
        items: list[VisitSessionRead]
    ''',
)

add(
    "app/validators/doctor_panel.py",
    '''\
    """Doctor panel validators — Phase 13.2."""
    from __future__ import annotations
    from shared.exceptions import AppError
    from app.models.types import VisitSessionAction, VisitSessionStatus

    ALLOWED: dict[VisitSessionAction, set[VisitSessionStatus]] = {
        VisitSessionAction.CALL_NEXT: {VisitSessionStatus.QUEUED},
        VisitSessionAction.START: {VisitSessionStatus.QUEUED},
        VisitSessionAction.FINISH: {VisitSessionStatus.IN_PROGRESS},
        VisitSessionAction.DEFER: {VisitSessionStatus.QUEUED, VisitSessionStatus.IN_PROGRESS},
    }
    TARGET: dict[VisitSessionAction, VisitSessionStatus] = {
        VisitSessionAction.CALL_NEXT: VisitSessionStatus.QUEUED,
        VisitSessionAction.START: VisitSessionStatus.IN_PROGRESS,
        VisitSessionAction.FINISH: VisitSessionStatus.COMPLETED,
        VisitSessionAction.DEFER: VisitSessionStatus.DEFERRED,
    }
    TERMINAL = frozenset({VisitSessionStatus.COMPLETED, VisitSessionStatus.CANCELLED})

    def ensure_visit_session_transition(*, action: VisitSessionAction, current: VisitSessionStatus) -> None:
        if current in TERMINAL:
            raise AppError("جلسه ویزیت در وضعیت پایانی است", status_code=409, error_code="visit_session_terminal")
        allowed = ALLOWED.get(action, set())
        if current not in allowed:
            raise AppError(
                "انتقال وضعیت جلسه ویزیت مجاز نیست",
                status_code=409,
                error_code="invalid_visit_session_transition",
                details={"from_status": current.value, "action": action.value},
            )

    def target_status_for(action: VisitSessionAction) -> VisitSessionStatus:
        return TARGET[action]
    ''',
)

add(
    "app/policies/doctor_panel.py",
    '''\
    """Visit session lifecycle policies — Phase 13.2."""
    from __future__ import annotations
    from app.models.types import VisitSessionAction, VisitSessionStatus
    from app.validators.doctor_panel import ensure_visit_session_transition, target_status_for

    class VisitSessionPolicy:
        def ensure_transition(self, *, action: VisitSessionAction, current: VisitSessionStatus) -> VisitSessionStatus:
            ensure_visit_session_transition(action=action, current=current)
            return target_status_for(action)
    ''',
)

add(
    "app/specifications/doctor_panel.py",
    '''\
    """Doctor panel list specifications — Phase 13.2."""
    from __future__ import annotations
    from dataclasses import dataclass
    from uuid import UUID
    from app.models.types import VisitSessionStatus

    ALLOWED_SORT_FIELDS = frozenset({"queue_position", "created_at", "started_at"})

    @dataclass
    class VisitSessionListSpec:
        doctor_id: UUID | None = None
        clinic_id: UUID | None = None
        status: VisitSessionStatus | None = None
        sort_by: str = "queue_position"
        sort_dir: str = "asc"
    ''',
)

add(
    "app/repositories/doctor_panel.py",
    '''\
    """Doctor panel repositories — Phase 13.2."""
    from __future__ import annotations
    from datetime import datetime, timezone
    from uuid import UUID
    from sqlalchemy import and_, func, select
    from app.models.doctor_panel import VisitNote, VisitSession
    from app.models.types import VisitSessionStatus
    from app.repositories.base import TenantBaseRepository
    from app.specifications.doctor_panel import VisitSessionListSpec

    class VisitSessionRepository(TenantBaseRepository[VisitSession]):
        model = VisitSession

        async def get_by_code(self, tenant_id: UUID, code: str) -> VisitSession | None:
            stmt = select(VisitSession).where(
                VisitSession.tenant_id == tenant_id,
                VisitSession.code == code,
                VisitSession.is_deleted.is_(False),
            )
            result = await self.session.execute(stmt)
            return result.scalar_one_or_none()

        async def get_by_appointment(self, tenant_id: UUID, appointment_id: UUID) -> VisitSession | None:
            stmt = select(VisitSession).where(
                VisitSession.tenant_id == tenant_id,
                VisitSession.appointment_id == appointment_id,
                VisitSession.is_deleted.is_(False),
            )
            result = await self.session.execute(stmt)
            return result.scalar_one_or_none()

        def _filter_clauses(self, tenant_id: UUID, spec: VisitSessionListSpec | None):
            clauses = [VisitSession.tenant_id == tenant_id, VisitSession.is_deleted.is_(False)]
            if spec is None:
                return clauses
            if spec.doctor_id is not None:
                clauses.append(VisitSession.doctor_id == spec.doctor_id)
            if spec.clinic_id is not None:
                clauses.append(VisitSession.clinic_id == spec.clinic_id)
            if spec.status is not None:
                clauses.append(VisitSession.status == spec.status)
            return clauses

        async def list_filtered(self, tenant_id: UUID, *, offset: int = 0, limit: int = 20, spec: VisitSessionListSpec | None = None):
            clauses = self._filter_clauses(tenant_id, spec)
            sort_col = getattr(VisitSession, spec.sort_by if spec else "queue_position", VisitSession.queue_position)
            order = sort_col.asc() if spec and spec.sort_dir == "asc" else sort_col.desc()
            stmt = select(VisitSession).where(and_(*clauses)).order_by(order).offset(offset).limit(limit)
            result = await self.session.execute(stmt)
            return result.scalars().all()

        async def count_by_status(self, tenant_id: UUID, *, doctor_id: UUID, status: VisitSessionStatus) -> int:
            stmt = select(func.count()).select_from(VisitSession).where(
                VisitSession.tenant_id == tenant_id,
                VisitSession.doctor_id == doctor_id,
                VisitSession.status == status,
                VisitSession.is_deleted.is_(False),
            )
            result = await self.session.execute(stmt)
            return int(result.scalar_one())

        async def count_completed_today(self, tenant_id: UUID, *, doctor_id: UUID) -> int:
            today = datetime.now(timezone.utc).date()
            stmt = select(func.count()).select_from(VisitSession).where(
                VisitSession.tenant_id == tenant_id,
                VisitSession.doctor_id == doctor_id,
                VisitSession.status == VisitSessionStatus.COMPLETED,
                VisitSession.is_deleted.is_(False),
                func.date(VisitSession.finished_at) == today,
            )
            result = await self.session.execute(stmt)
            return int(result.scalar_one())

    class VisitNoteRepository(TenantBaseRepository[VisitNote]):
        model = VisitNote

        async def get_by_code(self, tenant_id: UUID, code: str) -> VisitNote | None:
            stmt = select(VisitNote).where(
                VisitNote.tenant_id == tenant_id,
                VisitNote.code == code,
                VisitNote.is_deleted.is_(False),
            )
            result = await self.session.execute(stmt)
            return result.scalar_one_or_none()

        async def list_by_session(self, tenant_id: UUID, visit_session_id: UUID):
            stmt = select(VisitNote).where(
                VisitNote.tenant_id == tenant_id,
                VisitNote.visit_session_id == visit_session_id,
                VisitNote.is_deleted.is_(False),
            )
            result = await self.session.execute(stmt)
            return result.scalars().all()
    ''',
)

if __name__ == "__main__":
    for rel, content in FILES.items():
        path = ROOT / rel
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(content, encoding="utf-8")
        print(f"wrote {rel}")
