from fastapi import HTTPException, status
from sqlalchemy.orm import Session
from datetime import timedelta
import logging
from zoneinfo import ZoneInfo

from app.core.security import verify_refresh_token, create_access_token, generate_verification_code
from app.core.time import now
from app.core.config import settings
from app.models.password_reset import PasswordReset
from app.services.user_service import UserService
from app.services.email_service import send_verification_email

logger = logging.getLogger('adimsayar')

class AuthService:
    @staticmethod
    def refresh_token(refresh_token: str) -> dict:
        subject = verify_refresh_token(refresh_token)
        if subject is None:
            logger.warning("Invalid refresh token")
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid refresh token"
            )
        new_access_token = create_access_token(subject=subject)
        return {"access_token": new_access_token, "token_type": "bearer"}

    @staticmethod
    def forgot_password(db: Session, email: str) -> dict:
        user = UserService.get_user_by_email(db, email)
        if not user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="User with provided email not found"
            )
        reset_code = generate_verification_code()
        reset_record = PasswordReset(user_id=user.id, reset_code=reset_code)
        db.add(reset_record)
        db.commit()

        if not send_verification_email(email, reset_code):
            raise HTTPException(
                status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                detail="Failed to send verification email"
            )

        return {"message": "Reset code has been sent to your email address."}

    @staticmethod
    def verify_reset_code(db: Session, email: str, reset_code: str) -> dict:
        user = UserService.get_user_by_email(db, email)
        if not user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="User not found"
            )

        reset_record = (
            db.query(PasswordReset)
            .filter(
                PasswordReset.user_id == user.id,
                PasswordReset.reset_code == reset_code
            )
            .order_by(PasswordReset.created_at.desc())
            .first()
        )
        if not reset_record:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid reset code"
            )

        # 만약 reset_record.created_at이 naive라면 Istanbul 현지 시간으로 간주
        expiry_time = reset_record.created_at
        if expiry_time.tzinfo is None:
            expiry_time = expiry_time.replace(tzinfo=ZoneInfo(settings.TIMEZONE))
        expiry_time += timedelta(minutes=10)
        
        current_time = now()  # now()는 Istanbul 현지 시간을 반환
        if current_time > expiry_time:
            reset_record.is_valid = 0
            db.commit()
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Reset code expired"
            )
        
        if reset_record.is_valid != 1:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Reset code has already been used"
            )
        
        reset_record.is_valid = 0
        db.commit()

        return {"message": "Reset code verified successfully"}

    @staticmethod
    def change_password(db: Session, email: str, reset_code: str, new_password: str) -> dict:
        user = UserService.get_user_by_email(db, email)
        if not user:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="User not found"
            )

        reset_record = (
            db.query(PasswordReset)
            .filter(
                PasswordReset.user_id == user.id,
                PasswordReset.reset_code == reset_code
            )
            .order_by(PasswordReset.created_at.desc())
            .first()
        )
        if not reset_record:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Invalid reset code"
            )

        if reset_record.is_valid != 0:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Reset code has not been verified"
            )

        allowed_window = timedelta(minutes=10)
        current_time = now()  # now()는 Istanbul 현지 시간을 반환
        if reset_record.created_at.tzinfo is None:
            record_time = reset_record.created_at.replace(tzinfo=ZoneInfo(settings.TIMEZONE))
        else:
            record_time = reset_record.created_at
        if current_time - record_time > allowed_window:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="Password reset request expired. Please request a new reset code."
            )

        UserService.reset_password(db, email, new_password)
        return {"message": "Password updated successfully."}
