# -*- coding: utf-8 -*-
# hub/ticket/domain/task.py

"""Доменная сущность задачи Ticket и сериализация её состояния."""

from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime
from typing import Any, Mapping

from .ticket_types import TicketTaskSnapshot


def _normalize_datetime(value: Any) -> datetime | None:
    """Преобразовать строку или datetime в datetime."""
    if value is None or value == "":
        return None
    if isinstance(value, datetime):
        return value
    if not isinstance(value, str):
        return None
    try:
        if "T" in value:
            return datetime.fromisoformat(value.replace("Z", "+00:00"))
        return datetime.strptime(value, "%Y-%m-%d %H:%M:%S")
    except ValueError:
        return None


def _normalize_color(value: Any) -> str:
    """Нормализовать представление цвета до hex-строки."""
    if isinstance(value, str) and value.startswith("#") and len(value) >= 4:
        return value
    name_getter = getattr(value, "name", None)
    if callable(name_getter):
        try:
            normalized = name_getter()
            if isinstance(normalized, str) and normalized.startswith("#"):
                return normalized
        except Exception as _exc:
            return "#FFFFFF"
    return "#FFFFFF"


def _normalize_int(value: Any, default: int | None = None) -> int | None:
    """Нормализовать число, сохранив валидное значение 0."""
    if value is None or value == "":
        return default
    try:
        return int(value)
    except (TypeError, ValueError):
        return default


@dataclass(slots=True)
class TicketTask:
    """Каноническая доменная задача Ticket."""

    task_id: int
    location: str
    state_code: int
    state_name: str
    action_text: str = ""
    color_hex: str = "#FFFFFF"
    created_at: datetime | None = None
    completed_at: datetime | None = None
    refused_from_state: int | None = None
    refusal_reason: str = ""
    assigned_specialist: str = ""
    specialist_photo: str = ""
    diagnostic_report_signed: bool = False
    repair_report_signed: bool = False
    acceptance_report_signed: bool = False
    sequence_number: int = 0

    @classmethod
    def from_record(cls, record: Mapping[str, Any]) -> TicketTask | None:
        """Создать задачу из записи файлового хранилища."""
        raw_task_id = record.get("button_id")
        if raw_task_id is None:
            return None
        try:
            task_id = int(raw_task_id)
        except (TypeError, ValueError):
            return None
        return cls(
            task_id=task_id,
            location=str(record.get("location", "")),
            state_code=_normalize_int(record.get("state"), 1) or 0,
            state_name=str(record.get("state_name", "")),
            action_text=str(record.get("action", "")),
            color_hex=_normalize_color(record.get("color", "#FFFFFF")),
            created_at=_normalize_datetime(record.get("created_time")) or datetime.now(),
            completed_at=_normalize_datetime(record.get("completed_time")),
            refused_from_state=_normalize_int(record.get("refused_from_state")),
            refusal_reason=str(record.get("refusal_reason", "")),
            assigned_specialist=str(record.get("assigned_specialist", "")),
            specialist_photo=str(record.get("specialist_photo", "")),
            diagnostic_report_signed=bool(record.get("diagnostic_report_signed", False)),
            repair_report_signed=bool(record.get("repair_report_signed", False)),
            acceptance_report_signed=bool(record.get("acceptance_report_signed", False)),
            sequence_number=_normalize_int(record.get("sequence_number"), 0) or 0,
        )

    @classmethod
    def from_snapshot(cls, snapshot: TicketTaskSnapshot) -> TicketTask:
        """Создать доменную сущность из snapshot."""
        return cls(
            task_id=snapshot.task_id,
            location=snapshot.location,
            state_code=snapshot.state_code,
            state_name=snapshot.state_name,
            action_text=snapshot.action_text,
            color_hex=snapshot.color_hex,
            created_at=snapshot.created_at,
            completed_at=snapshot.completed_at,
            refused_from_state=snapshot.refused_from_state,
            refusal_reason=snapshot.refusal_reason,
            assigned_specialist=snapshot.assigned_specialist,
            specialist_photo=snapshot.specialist_photo,
            diagnostic_report_signed=snapshot.diagnostic_report_signed,
            repair_report_signed=snapshot.repair_report_signed,
            acceptance_report_signed=snapshot.acceptance_report_signed,
            sequence_number=snapshot.sequence_number,
        )

    def to_record(self) -> dict[str, Any]:
        """Преобразовать доменную сущность в запись для JSON."""
        return {
            "button_id": self.task_id,
            "location": self.location,
            "state": self.state_code,
            "action": self.action_text,
            "state_name": self.state_name,
            "color": self.color_hex,
            "created_time": self.created_at,
            "completed_time": self.completed_at,
            "refused_from_state": self.refused_from_state,
            "refusal_reason": self.refusal_reason,
            "assigned_specialist": self.assigned_specialist,
            "specialist_photo": self.specialist_photo,
            "diagnostic_report_signed": self.diagnostic_report_signed,
            "repair_report_signed": self.repair_report_signed,
            "acceptance_report_signed": self.acceptance_report_signed,
            "sequence_number": self.sequence_number,
        }

    def to_snapshot(self) -> TicketTaskSnapshot:
        """Вернуть неизменяемый снимок задачи для внешних слоёв."""
        return TicketTaskSnapshot(
            task_id=self.task_id,
            location=self.location,
            state_code=self.state_code,
            state_name=self.state_name,
            action_text=self.action_text,
            color_hex=self.color_hex,
            created_at=self.created_at,
            completed_at=self.completed_at,
            refused_from_state=self.refused_from_state,
            refusal_reason=self.refusal_reason,
            assigned_specialist=self.assigned_specialist,
            specialist_photo=self.specialist_photo,
            diagnostic_report_signed=self.diagnostic_report_signed,
            repair_report_signed=self.repair_report_signed,
            acceptance_report_signed=self.acceptance_report_signed,
            sequence_number=self.sequence_number,
        )
