from sqlalchemy import select

from zbt.domains.service_request.models import MaterialRecognition, ServiceRequest
from zbt.domains.service_request.repository import ServiceRequestRepository
from zbt.infrastructure.mysql.core_models import (
    MaterialRecognitionRecord,
    ServiceRequestRecord,
)
from zbt.infrastructure.mysql.repositories import SessionFactory


class SqlAlchemyServiceRequestRepository(ServiceRequestRepository):
    def __init__(self, session_factory: SessionFactory) -> None:
        self._session_factory = session_factory

    def save_recognition(self, recognition: MaterialRecognition) -> None:
        with self._session_factory() as session:
            session.merge(
                MaterialRecognitionRecord(
                    id=recognition.id,
                    h5_user_id=recognition.user_id,
                    policy_id=recognition.policy_id,
                    material_type=recognition.material_type,
                    source_name=recognition.source_name,
                    media_type=recognition.media_type,
                    fields_json=recognition.fields,
                    confidence=recognition.confidence,
                    warnings_json=list(recognition.warnings),
                    status=recognition.status,
                    created_at=recognition.created_at,
                    confirmed_at=recognition.confirmed_at,
                )
            )
            session.commit()

    def get_recognition(self, recognition_id: str) -> MaterialRecognition | None:
        with self._session_factory() as session:
            record = session.get(MaterialRecognitionRecord, recognition_id)
            return self._recognition(record) if record else None

    def save_request(self, request: ServiceRequest) -> None:
        with self._session_factory() as session:
            session.merge(
                ServiceRequestRecord(
                    id=request.id,
                    request_no=request.request_no,
                    h5_user_id=request.user_id,
                    policy_id=request.policy_id,
                    request_type=request.request_type,
                    recognition_id=request.recognition_id,
                    confirmed_fields_json=request.confirmed_fields,
                    status=request.status,
                    submitted_at=request.submitted_at,
                    reviewed_by=request.reviewed_by,
                    review_note=request.review_note,
                    reviewed_at=request.reviewed_at,
                )
            )
            session.commit()

    def get_request(self, request_id: str) -> ServiceRequest | None:
        with self._session_factory() as session:
            record = session.get(ServiceRequestRecord, request_id)
            return self._request(record) if record else None

    def list_requests(self, user_id: str | None = None) -> list[ServiceRequest]:
        with self._session_factory() as session:
            statement = select(ServiceRequestRecord).order_by(
                ServiceRequestRecord.submitted_at.desc()
            )
            if user_id is not None:
                statement = statement.where(ServiceRequestRecord.h5_user_id == user_id)
            return [self._request(record) for record in session.scalars(statement)]

    @staticmethod
    def _recognition(record: MaterialRecognitionRecord) -> MaterialRecognition:
        return MaterialRecognition(
            id=record.id,
            user_id=record.h5_user_id,
            policy_id=record.policy_id,
            material_type=record.material_type,
            source_name=record.source_name,
            media_type=record.media_type,
            fields=dict(record.fields_json),
            confidence=record.confidence,
            warnings=tuple(record.warnings_json),
            status=record.status,
            created_at=record.created_at,
            confirmed_at=record.confirmed_at,
        )

    @staticmethod
    def _request(record: ServiceRequestRecord) -> ServiceRequest:
        return ServiceRequest(
            id=record.id,
            request_no=record.request_no,
            user_id=record.h5_user_id,
            policy_id=record.policy_id,
            request_type=record.request_type,
            recognition_id=record.recognition_id,
            confirmed_fields=dict(record.confirmed_fields_json),
            status=record.status,
            submitted_at=record.submitted_at,
            reviewed_by=record.reviewed_by,
            review_note=record.review_note,
            reviewed_at=record.reviewed_at,
        )
