# -*- coding: utf-8 -*-
# hub/ticket/ui/task_view_formatters.py

"""Форматирование отображения задач Ticket для карточек и деталей."""

from __future__ import annotations

from datetime import datetime
from pathlib import Path

from domain import TicketTaskSnapshot, parse_location_parts
from domain.ticket_constants import (
    STATE_COMPLETED,
    STATE_CONFIRMATION,
    STATE_IN_PROGRESS,
    STATE_REFUSED,
    STATE_TODO,
)

_REPO_ROOT = Path(__file__).resolve().parents[3]
_TICKET_ICONS_DIR = _REPO_ROOT / "gui" / "icons"
_TICKET_SPECIALISTS_DIR = _TICKET_ICONS_DIR / "specialists"
_DEFAULT_SPECIALIST_PHOTO = "specialist.png"
_DEFAULT_STAGE_ICON = "close.png"
_STAGE_ICON_FILENAMES = {
    "specialist": "face-man-shimmer-outline.png",
    "diagnostic": "wrench-outline.png",
    "repair": "wrench-outline.png",
    "acceptance": "pencil-outline.png",
}
_SPECIALIST_CARD_INFO = {
    "Иванов Алексей Сергеевич": ("Иванов А.С.", "Инженер-электроник", "specialist1.png"),
    "Петрова Мария Владимировна": ("Петрова М.В.", "Техник-рентгенолог", "specialist2.png"),
    "Сидоров Дмитрий Иванович": ("Сидоров Д.И.", "Инженер КИПиА", "specialist3.png"),
    "Козлова Анна Петровна": ("Козлова А.П.", "Специалист по ТО", "specialist4.png"),
    "Васильев Сергей Николаевич": ("Васильев С.Н.", "Инженер-программист", "specialist5.png"),
    "Николаева Ольга Дмитриевна": ("Николаева О.Д.", "Техник-электрик", "specialist6.png"),
    "Фёдоров Андрей Викторович": ("Фёдоров А.В.", "Инженер-механик", "specialist7.png"),
    "Орлова Екатерина Александровна": ("Орлова Е.А.", "Специалист по диагностике", "specialist8.png"),
}


def build_task_title(task: TicketTaskSnapshot) -> str:
    if task.sequence_number:
        return f"Задача #{task.sequence_number}"
    return f"Задача #{task.task_id}"


def build_task_card_subtitle(task: TicketTaskSnapshot) -> str:
    specialist_text = task.assigned_specialist.strip() or "Специалист не назначен"
    return "\n".join(
        (
            task.location or "Локация не указана",
            specialist_text,
            build_documents_summary(task),
        )
    )


def build_documents_summary(task: TicketTaskSnapshot) -> str:
    return (
        f"Д: {_bool_text(task.diagnostic_report_signed)} | "
        f"Р: {_bool_text(task.repair_report_signed)} | "
        f"А: {_bool_text(task.acceptance_report_signed)}"
    )


def split_task_location(location: str) -> tuple[str, str, str]:
    normalized_location = (location or "").strip()
    if not normalized_location:
        return ("Локация не указана", "Аппарат не указан", "Кабинет не указан")
    institution, room, device = parse_location_parts(normalized_location)
    institution = institution or "Локация не указана"
    device = device or "Аппарат не указан"
    room = room or "Кабинет не указан"

    return (
        shorten_card_text(institution, limit=36),
        shorten_card_text(device, limit=34),
        shorten_card_text(room, limit=24),
    )


def build_task_footer_text(task: TicketTaskSnapshot) -> str:
    return build_specialist_card_text(task.assigned_specialist)


def build_task_fault_title(task: TicketTaskSnapshot) -> str:
    """Извлечь краткий заголовок неисправности из строки локации задачи.

    Формат локации, формируемый формой создания заявки:
    «Учреждение (Аппарат — Краткий заголовок, каб. №)».
    Парсер `parse_location_parts` возвращает блок «Аппарат — Краткий
    заголовок» в позиции `device`. Заголовок неисправности — это
    содержимое после разделителя « — ». При его отсутствии (например,
    для тестовых задач без формы) возвращается само устройство, а в
    предельном случае — оригинальная строка локации.
    """
    institution, _device, _room = split_task_location(task.location)
    _, _, raw_device = parse_location_parts(task.location or "")
    device_text = raw_device.strip() or institution
    separator = " — "
    if separator in device_text:
        title = device_text.split(separator, 1)[1].strip()
        if title:
            return shorten_card_text(title, limit=64)
    if device_text:
        return shorten_card_text(device_text, limit=64)
    return shorten_card_text(task.location or "Заголовок не указан", limit=64)


def build_task_stage_flags(task: TicketTaskSnapshot) -> tuple[tuple[str, bool], ...]:
    return (
        ("specialist", bool(task.assigned_specialist.strip())),
        ("diagnostic", bool(task.diagnostic_report_signed)),
        ("repair", bool(task.repair_report_signed)),
        ("acceptance", bool(task.acceptance_report_signed)),
    )


def build_specialist_initials(specialist_name: str) -> str:
    normalized_name = (specialist_name or "").strip()
    if not normalized_name:
        return "?"
    parts = [part for part in normalized_name.split() if part]
    if len(parts) >= 2:
        return f"{parts[0][0]}{parts[1][0]}".upper()
    if len(parts[0]) >= 2:
        return parts[0][:2].upper()
    return parts[0][:1].upper()


def build_specialist_card_text(specialist_name: str) -> str:
    specialist_info = build_specialist_card_info(specialist_name)
    short_name = specialist_info["short_name"]
    position = specialist_info["position"]
    if not short_name:
        return "Специалист не назначен"
    if not position:
        return shorten_card_text(short_name, limit=40)
    return shorten_card_text(f"{short_name} • {position}", limit=42)


def build_specialist_card_info(specialist_name: str) -> dict[str, str]:
    normalized_name = (specialist_name or "").strip()
    if not normalized_name:
        return {"short_name": "", "position": "", "photo": ""}
    short_name, position, photo_filename = _SPECIALIST_CARD_INFO.get(
        normalized_name,
        _fallback_specialist_card_info(normalized_name),
    )
    return {
        "short_name": short_name,
        "position": position,
        "photo": photo_filename,
    }


def build_specialist_photo_path(specialist_name: str, photo_filename: str) -> str:
    normalized_filename = (photo_filename or "").strip()
    if normalized_filename:
        return _resolve_specialist_photo_path(normalized_filename)
    specialist_info = build_specialist_card_info(specialist_name)
    photo_from_mapping = specialist_info.get("photo", "").strip()
    if not photo_from_mapping:
        return ""
    return _resolve_specialist_photo_path(photo_from_mapping)


def build_stage_icon_path(stage_key: str, is_active: bool) -> str:
    filename = _STAGE_ICON_FILENAMES.get(stage_key, _DEFAULT_STAGE_ICON) if is_active else _DEFAULT_STAGE_ICON
    icon_path = _TICKET_ICONS_DIR / filename
    if not icon_path.exists():
        return ""
    return str(icon_path)


def shorten_card_text(text: str, limit: int) -> str:
    normalized_text = " ".join((text or "").split())
    if len(normalized_text) <= limit:
        return normalized_text
    if limit <= 3:
        return normalized_text[:limit]
    return f"{normalized_text[:limit - 3].rstrip()}..."


def build_stage_rows(task: TicketTaskSnapshot) -> tuple[tuple[str, str], ...]:
    specialist_status = (
        f"Назначен: {task.assigned_specialist}"
        if task.assigned_specialist.strip()
        else "Не назначен"
    )
    diagnostic_status = (
        "Диагностический отчёт подписан"
        if task.diagnostic_report_signed
        else "Диагностический отчёт ожидается"
    )
    repair_status = (
        "Ремонтный отчёт подписан"
        if task.repair_report_signed
        else "Ремонтный отчёт ожидается"
    )
    acceptance_status = (
        "Акт приёмки подписан"
        if task.acceptance_report_signed
        else "Акт приёмки ожидается"
    )
    return (
        ("Специалист", specialist_status),
        ("Диагностика", diagnostic_status),
        ("Ремонт", repair_status),
        ("Приёмка", acceptance_status),
    )


def build_action_hint(task: TicketTaskSnapshot) -> str:
    if task.state_code == STATE_TODO:
        return "Назначьте специалиста и переведите задачу аппаратной кнопкой в работу."
    if task.state_code == STATE_IN_PROGRESS:
        if not task.assigned_specialist.strip():
            return "Сначала назначьте специалиста, затем подпишите диагностический и ремонтный отчёты."
        if not task.diagnostic_report_signed or not task.repair_report_signed:
            return "Для перехода к подтверждению подпишите диагностический и ремонтный отчёты."
        return "Отчёты готовы. Следующий аппаратный переход переведёт задачу к подтверждению."
    if task.state_code == STATE_CONFIRMATION:
        if not task.acceptance_report_signed:
            return "Подпишите акт приёмки, чтобы задача могла перейти в выполненные."
        return "Акт готов. Следующий аппаратный переход завершит задачу."
    if task.state_code == STATE_COMPLETED:
        return "Задача завершена. Её можно переместить в архив."
    if task.state_code == STATE_REFUSED:
        return "Задача завершилась отказом. Её можно переместить в архив."
    return "Архивная запись доступна только для просмотра."


def format_datetime(value: datetime | None) -> str:
    if value is None:
        return "—"
    return value.strftime("%d.%m.%Y %H:%M")


def can_assign_specialist(task: TicketTaskSnapshot) -> bool:
    return task.state_code in {STATE_TODO, STATE_IN_PROGRESS, STATE_CONFIRMATION}


def can_sign_diagnostic(task: TicketTaskSnapshot) -> bool:
    return (
        task.state_code == STATE_IN_PROGRESS
        and bool(task.assigned_specialist.strip())
        and not task.diagnostic_report_signed
    )


def can_sign_repair(task: TicketTaskSnapshot) -> bool:
    return (
        task.state_code == STATE_IN_PROGRESS
        and bool(task.assigned_specialist.strip())
        and not task.repair_report_signed
    )


def can_sign_acceptance(task: TicketTaskSnapshot) -> bool:
    return task.state_code == STATE_CONFIRMATION and not task.acceptance_report_signed


def can_archive(task: TicketTaskSnapshot) -> bool:
    return task.state_code in {STATE_COMPLETED, STATE_REFUSED}


def _bool_text(value: bool) -> str:
    return "Да" if value else "Нет"


def _fallback_specialist_card_info(specialist_name: str) -> tuple[str, str, str]:
    parts = [part for part in specialist_name.split() if part]
    if len(parts) >= 3:
        initials = f"{parts[1][0]}.{parts[2][0]}."
        return (f"{parts[0]} {initials}", "Специалист", "")
    return (specialist_name, "Специалист", "")


def _resolve_specialist_photo_path(photo_filename: str) -> str:
    photo_path = _TICKET_SPECIALISTS_DIR / photo_filename
    if photo_path.exists():
        return str(photo_path)
    fallback_path = _TICKET_SPECIALISTS_DIR / _DEFAULT_SPECIALIST_PHOTO
    if fallback_path.exists():
        return str(fallback_path)
    return ""
