# -*- coding: utf-8 -*-
# hub/ticket/application/document_flow_service.py

"""Application-сервис генерации документов Ticket."""

from __future__ import annotations

from typing import Callable

from domain import TicketDocumentSnapshot, TicketTaskSnapshot, parse_location_parts
from domain.task import TicketTask
from domain.ticket_constants import STATE_CONFIRMATION, STATE_IN_PROGRESS
from state import TicketDocumentRepository, TicketStateApi


class DocumentFlowService:
    """Канонический document-flow Ticket поверх state и файлового репозитория."""

    def __init__(
        self,
        state: TicketStateApi,
        repository: TicketDocumentRepository | None = None,
    ):
        self._state = state
        self._repository = repository or TicketDocumentRepository()

    def create_diagnostic_report(
        self,
        task_id: int,
        initial_cause: str,
        actual_cause: str,
    ) -> TicketDocumentSnapshot:
        task = self._get_task_or_raise(task_id)
        self._ensure_in_progress(task, "Диагностический отчёт")
        self._ensure_specialist_assigned(task)
        if task.diagnostic_report_signed:
            raise ValueError("Диагностический отчёт уже подписан.")
        if not initial_cause.strip() or not actual_cause.strip():
            raise ValueError("Заполните первичное и вторичное заключения.")
        payload = self._base_payload(task)
        payload.update(
            {
                "initial_cause": initial_cause.strip(),
                "actual_cause": actual_cause.strip(),
            }
        )
        document = self._save_document(
            task=task,
            document_type="diagnostic",
            title=f"Диагностический отчёт по задаче #{task.sequence_number or task.task_id}",
            summary=actual_cause.strip(),
            payload=payload,
            content_builder=self._render_diagnostic_report,
        )
        self._state.sign_report(task.task_id, "diagnostic")
        return document

    def create_repair_report(
        self,
        task_id: int,
        work_done: str,
        used_parts: str,
        recommendations: str,
    ) -> TicketDocumentSnapshot:
        task = self._get_task_or_raise(task_id)
        self._ensure_in_progress(task, "Ремонтный отчёт")
        self._ensure_specialist_assigned(task)
        if task.repair_report_signed:
            raise ValueError("Ремонтный отчёт уже подписан.")
        if not work_done.strip():
            raise ValueError("Заполните поле 'Выполненные работы'.")
        payload = self._base_payload(task)
        payload.update(
            {
                "work_done": work_done.strip(),
                "used_parts": used_parts.strip(),
                "recommendations": recommendations.strip(),
            }
        )
        document = self._save_document(
            task=task,
            document_type="repair",
            title=f"Ремонтный отчёт по задаче #{task.sequence_number or task.task_id}",
            summary=work_done.strip(),
            payload=payload,
            content_builder=self._render_repair_report,
        )
        self._state.sign_report(task.task_id, "repair")
        return document

    def create_acceptance_report(
        self,
        task_id: int,
        work_description: str,
        executor_signature: str,
        customer_signature: str,
    ) -> TicketDocumentSnapshot:
        task = self._get_task_or_raise(task_id)
        if task.state_code != STATE_CONFIRMATION:
            raise ValueError("Акт приёмки доступен только в состоянии подтверждения.")
        if task.acceptance_report_signed:
            raise ValueError("Акт приёмки уже подписан.")
        if not task.diagnostic_report_signed or not task.repair_report_signed:
            raise ValueError("Сначала подпишите диагностический и ремонтный отчёты.")
        if not work_description.strip():
            raise ValueError("Заполните описание выполненных работ.")
        if not executor_signature.strip() or not customer_signature.strip():
            raise ValueError("Укажите подписи исполнителя и заказчика.")
        payload = self._base_payload(task)
        payload.update(
            {
                "work_description": work_description.strip(),
                "executor_signature": executor_signature.strip(),
                "customer_signature": customer_signature.strip(),
            }
        )
        document = self._save_document(
            task=task,
            document_type="acceptance",
            title=f"Акт приёмки по задаче #{task.sequence_number or task.task_id}",
            summary=work_description.strip(),
            payload=payload,
            content_builder=self._render_acceptance_report,
        )
        task_data = TicketTask.from_snapshot(task).to_record()
        task_data["acceptance_report_signed"] = True
        self._state.update_task(task_data)
        return document

    def list_documents(
        self,
        document_type: str | None = None,
    ) -> list[TicketDocumentSnapshot]:
        """Вернуть отсортированный список документов Ticket."""
        return self._repository.list_documents(document_type)

    def _save_document(
        self,
        task: TicketTaskSnapshot,
        document_type: str,
        title: str,
        summary: str,
        payload: dict[str, str],
        content_builder: Callable[[dict[str, str]], str],
    ) -> TicketDocumentSnapshot:
        document = self._repository.save_document(
            task=task,
            document_type=document_type,
            title=title,
            summary=summary,
            content=content_builder(payload),
            payload=payload,
        )
        if document is None:
            raise ValueError("Не удалось сохранить документ Ticket.")
        return document

    def _get_task_or_raise(self, task_id: int) -> TicketTaskSnapshot:
        task = self._state.get_task(task_id)
        if task is None:
            raise ValueError(f"Задача #{task_id} не найдена.")
        return task

    @staticmethod
    def _ensure_in_progress(task: TicketTaskSnapshot, document_name: str) -> None:
        if task.state_code != STATE_IN_PROGRESS:
            raise ValueError(f"{document_name} можно подписать только в состоянии 'В работе'.")

    @staticmethod
    def _ensure_specialist_assigned(task: TicketTaskSnapshot) -> None:
        if not task.assigned_specialist.strip():
            raise ValueError("Сначала назначьте специалиста.")

    @staticmethod
    def _base_payload(task: TicketTaskSnapshot) -> dict[str, str]:
        institution, room, device = parse_location_parts(task.location)
        return {
            "task_id": str(task.sequence_number or task.task_id),
            "institution": institution,
            "room": room,
            "device": device,
            "location": task.location,
            "specialist": task.assigned_specialist,
        }

    @staticmethod
    def _render_diagnostic_report(payload: dict[str, str]) -> str:
        return (
            f"ДИАГНОСТИЧЕСКИЙ ОТЧЁТ #{payload['task_id']}\n\n"
            f"Учреждение: {payload.get('institution', '—')}\n"
            f"Оборудование: {payload.get('device', '—')}\n"
            f"Кабинет: {payload.get('room', '—')}\n"
            f"Специалист: {payload.get('specialist', '—')}\n\n"
            "Первичное заключение:\n"
            f"{payload.get('initial_cause', '—')}\n\n"
            "Вторичное заключение:\n"
            f"{payload.get('actual_cause', '—')}\n"
        )

    @staticmethod
    def _render_repair_report(payload: dict[str, str]) -> str:
        return (
            f"РЕМОНТНЫЙ ОТЧЁТ #{payload['task_id']}\n\n"
            f"Учреждение: {payload.get('institution', '—')}\n"
            f"Оборудование: {payload.get('device', '—')}\n"
            f"Кабинет: {payload.get('room', '—')}\n"
            f"Специалист: {payload.get('specialist', '—')}\n\n"
            "Выполненные работы:\n"
            f"{payload.get('work_done', '—')}\n\n"
            "Использованные запчасти:\n"
            f"{payload.get('used_parts', '—')}\n\n"
            "Рекомендации:\n"
            f"{payload.get('recommendations', '—')}\n"
        )

    @staticmethod
    def _render_acceptance_report(payload: dict[str, str]) -> str:
        return (
            f"АКТ ПРИЁМКИ #{payload['task_id']}\n\n"
            f"Учреждение: {payload.get('institution', '—')}\n"
            f"Оборудование: {payload.get('device', '—')}\n"
            f"Кабинет: {payload.get('room', '—')}\n"
            f"Специалист: {payload.get('specialist', '—')}\n\n"
            "Описание выполненных работ:\n"
            f"{payload.get('work_description', '—')}\n\n"
            "Исполнитель:\n"
            f"{payload.get('executor_signature', '—')}\n\n"
            "Заказчик:\n"
            f"{payload.get('customer_signature', '—')}\n"
        )
