from __future__ import annotations

from sqlalchemy.orm import Session

from packages.adapters.sqlalchemy_impl.models import UserModel
from packages.domain.entities import User
from packages.ports.user_repository import UserRepository


class SQLAlchemyUserRepository(UserRepository):
    def __init__(self, session: Session):
        self.session = session

    def save(self, user: User) -> None:
        model = self.session.get(UserModel, user.id)
        if model is None:
            model = UserModel(id=user.id)
            self.session.add(model)

        model.email = user.email
        model.username = user.username
        model.display_name = user.display_name
        model.password_hash = user.password_hash
        model.email_verified = user.email_verified
        model.email_verification_token = user.email_verification_token
        model.password_reset_token = user.password_reset_token
        model.password_reset_expires_at = user.password_reset_expires_at
        model.last_login_at = user.last_login_at
        model.last_login_ip = user.last_login_ip
        model.subscription_plan = user.subscription_plan
        model.subscription_status = user.subscription_status
        model.subscription_expires_at = user.subscription_expires_at
        model.max_projects = user.max_projects
        model.max_storage_gb = user.max_storage_gb
        model.is_admin = user.is_admin
        model.wechat_openid = user.wechat_openid
        model.wechat_unionid = user.wechat_unionid
        model.created_at = user.created_at

        self.session.commit()
        self.session.refresh(model)

    def find_by_id(self, user_id: str) -> User | None:
        return self._to_entity(self.session.get(UserModel, user_id))

    def find_by_email(self, email: str) -> User | None:
        model = self.session.query(UserModel).filter(UserModel.email == email.strip().lower()).first()
        return self._to_entity(model)

    def find_by_username(self, username: str) -> User | None:
        model = self.session.query(UserModel).filter(UserModel.username == username.strip()).first()
        return self._to_entity(model)

    def find_by_wechat_openid(self, openid: str) -> User | None:
        model = self.session.query(UserModel).filter(UserModel.wechat_openid == openid.strip()).first()
        return self._to_entity(model)

    def find_by_wechat_unionid(self, unionid: str) -> User | None:
        if not unionid or not unionid.strip():
            return None
        model = self.session.query(UserModel).filter(UserModel.wechat_unionid == unionid.strip()).first()
        return self._to_entity(model)

    def find_by_verification_token(self, token: str) -> User | None:
        model = self.session.query(UserModel).filter(UserModel.email_verification_token == token).first()
        return self._to_entity(model)

    def find_by_password_reset_token(self, token: str) -> User | None:
        model = self.session.query(UserModel).filter(UserModel.password_reset_token == token).first()
        return self._to_entity(model)

    def delete(self, user_id: str) -> bool:
        model = self.session.get(UserModel, user_id)
        if model is None:
            return False
        self.session.delete(model)
        self.session.commit()
        return True

    @staticmethod
    def _to_entity(model: UserModel | None) -> User | None:
        if model is None:
            return None
        return User(
            id=model.id,
            email=model.email,
            username=model.username or "",
            display_name=model.display_name,
            password_hash=model.password_hash,
            email_verified=model.email_verified,
            email_verification_token=model.email_verification_token,
            password_reset_token=model.password_reset_token,
            password_reset_expires_at=model.password_reset_expires_at,
            last_login_at=model.last_login_at,
            last_login_ip=model.last_login_ip,
            subscription_plan=model.subscription_plan or "free",
            subscription_status=model.subscription_status or "active",
            subscription_expires_at=model.subscription_expires_at,
            max_projects=model.max_projects or 3,
            max_storage_gb=model.max_storage_gb or 10,
            is_admin=model.is_admin or False,
            wechat_openid=model.wechat_openid,
            wechat_unionid=model.wechat_unionid,
            created_at=model.created_at,
        )
