"""SQLAlchemy implementation of VoiceCloneProfileRepository."""

from __future__ import annotations

from typing import Dict, List, Optional

from sqlalchemy.orm import Session

from packages.adapters.sqlalchemy_impl.models import VoiceCloneProfileModel
from packages.domain.voice_clone_profile import VoiceCloneProfile, VoiceCloneStatus


class SQLAlchemyVoiceCloneProfileRepository:
    """SQLAlchemy 音色克隆档案仓储。"""

    def __init__(self, session: Session) -> None:
        self.session = session

    def create(self, profile: VoiceCloneProfile) -> VoiceCloneProfile:
        model = VoiceCloneProfileModel(
            id=profile.id,
            user_id=profile.user_id,
            name=profile.name,
            description=profile.description,
            source_audio_url=profile.source_audio_url,
            voice_id=profile.voice_id,
            voice_model=profile.voice_model,
            language=profile.language,
            gender=profile.gender,
            status=profile.status,
            error_message=profile.error_message,
            retry_count=profile.retry_count,
            max_retries=profile.max_retries,
            metadata_=profile.metadata,
        )
        self.session.add(model)
        self.session.commit()
        self.session.refresh(model)
        return self._model_to_entity(model)

    def get(self, profile_id: str) -> Optional[VoiceCloneProfile]:
        model = (
            self.session.query(VoiceCloneProfileModel)
            .filter(
                VoiceCloneProfileModel.id == profile_id,
                VoiceCloneProfileModel.status != "deleted",
            )
            .first()
        )
        if model is None:
            return None
        return self._model_to_entity(model)

    def update(self, profile: VoiceCloneProfile) -> VoiceCloneProfile:
        model = self.session.query(VoiceCloneProfileModel).filter(VoiceCloneProfileModel.id == profile.id).first()
        if model is None:
            raise ValueError(f"VoiceCloneProfile {profile.id} not found")
        model.name = profile.name
        model.description = profile.description
        model.source_audio_url = profile.source_audio_url
        model.voice_id = profile.voice_id
        model.voice_model = profile.voice_model
        model.language = profile.language
        model.gender = profile.gender
        model.status = profile.status
        model.error_message = profile.error_message
        model.retry_count = profile.retry_count
        model.max_retries = profile.max_retries
        model.metadata_ = profile.metadata
        self.session.commit()
        self.session.refresh(model)
        return self._model_to_entity(model)

    def delete(self, profile_id: str) -> bool:
        model = self.session.query(VoiceCloneProfileModel).filter(VoiceCloneProfileModel.id == profile_id).first()
        if model is None:
            return False
        model.status = "deleted"
        self.session.commit()
        return True

    def list_by_user(
        self,
        user_id: str,
        *,
        status: Optional[str] = None,
        limit: int = 50,
        offset: int = 0,
    ) -> List[VoiceCloneProfile]:
        query = self.session.query(VoiceCloneProfileModel).filter(
            VoiceCloneProfileModel.user_id == user_id,
            VoiceCloneProfileModel.status != "deleted",
        )
        if status:
            query = query.filter(VoiceCloneProfileModel.status == status)
        query = query.order_by(VoiceCloneProfileModel.created_at.desc())
        models = query.offset(offset).limit(limit).all()
        return [self._model_to_entity(m) for m in models]

    def count_by_user(self, user_id: str, *, status: Optional[str] = None) -> int:
        query = self.session.query(VoiceCloneProfileModel).filter(
            VoiceCloneProfileModel.user_id == user_id,
            VoiceCloneProfileModel.status != "deleted",
        )
        if status:
            query = query.filter(VoiceCloneProfileModel.status == status)
        return query.count()

    def find_by_voice_id(self, voice_id: str) -> Optional[VoiceCloneProfile]:
        model = (
            self.session.query(VoiceCloneProfileModel)
            .filter(
                VoiceCloneProfileModel.voice_id == voice_id,
                VoiceCloneProfileModel.status != "deleted",
            )
            .first()
        )
        if model is None:
            return None
        return self._model_to_entity(model)

    def find_profile_ids_by_voice_ids(self, voice_ids: List[str]) -> Dict[str, str]:
        """批量查询 voice_id → profile_id 映射。用于填充统一列表的 voice_clone_profile_id。"""
        if not voice_ids:
            return {}
        rows = (
            self.session.query(
                VoiceCloneProfileModel.voice_id,
                VoiceCloneProfileModel.id,
            )
            .filter(
                VoiceCloneProfileModel.voice_id.in_(voice_ids),
                VoiceCloneProfileModel.status != "deleted",
            )
            .all()
        )
        return {voice_id: profile_id for voice_id, profile_id in rows}

    @staticmethod
    def _model_to_entity(model: VoiceCloneProfileModel) -> VoiceCloneProfile:
        return VoiceCloneProfile(
            id=model.id,
            user_id=model.user_id,
            name=model.name,
            description=model.description or "",
            source_audio_url=model.source_audio_url or "",
            voice_id=model.voice_id or "",
            voice_model=model.voice_model or "",
            language=model.language or "zh-CN",
            gender=model.gender or "unknown",
            status=VoiceCloneStatus(model.status) if model.status else VoiceCloneStatus.PENDING,
            error_message=model.error_message or "",
            retry_count=model.retry_count or 0,
            max_retries=model.max_retries or 3,
            metadata=model.metadata_ or {},
            created_at=model.created_at,
            updated_at=model.updated_at,
        )
