"""
Account management service for ThrillWiki.

Provides password validation, password changes, and email change functionality.
"""

import re
import secrets
from typing import TYPE_CHECKING

from django.core.mail import send_mail
from django.template.loader import render_to_string
from django.utils import timezone

if TYPE_CHECKING:
    from django.http import HttpRequest

    from apps.accounts.models import User


class AccountService:
    """
    Service for managing user account operations.

    Handles password validation, password changes, and email changes
    with proper verification flows.
    """

    # Password requirements
    MIN_PASSWORD_LENGTH = 8
    REQUIRE_UPPERCASE = True
    REQUIRE_LOWERCASE = True
    REQUIRE_NUMBERS = True

    @classmethod
    def validate_password(cls, password: str) -> bool:
        """
        Validate a password against security requirements.

        Args:
            password: The password to validate

        Returns:
            True if password meets requirements, False otherwise
        """
        if len(password) < cls.MIN_PASSWORD_LENGTH:
            return False

        if cls.REQUIRE_UPPERCASE and not re.search(r"[A-Z]", password):
            return False

        if cls.REQUIRE_LOWERCASE and not re.search(r"[a-z]", password):
            return False

        if cls.REQUIRE_NUMBERS and not re.search(r"[0-9]", password):
            return False

        return True

    @classmethod
    def change_password(
        cls,
        user: "User",
        old_password: str,
        new_password: str,
        request: "HttpRequest | None" = None,
    ) -> dict:
        """
        Change a user's password.

        Args:
            user: The user whose password to change
            old_password: The current password
            new_password: The new password
            request: Optional request for context

        Returns:
            Dict with 'success' boolean and 'message' string
        """
        # Verify old password
        if not user.check_password(old_password):
            return {
                "success": False,
                "message": "Current password is incorrect.",
            }

        # Validate new password
        if not cls.validate_password(new_password):
            return {
                "success": False,
                "message": f"New password must be at least {cls.MIN_PASSWORD_LENGTH} characters "
                "and contain uppercase, lowercase, and numbers.",
            }

        # Change the password
        user.set_password(new_password)
        user.save(update_fields=["password"])

        # Send confirmation email
        cls._send_password_change_confirmation(user, request)

        return {
            "success": True,
            "message": "Password changed successfully.",
        }

    @classmethod
    def _send_password_change_confirmation(
        cls,
        user: "User",
        request: "HttpRequest | None" = None,
    ) -> None:
        """Send a confirmation email after password change."""
        try:
            send_mail(
                subject="Password Changed - ThrillWiki",
                message=f"Hi {user.username},\n\nYour password has been changed successfully.\n\n"
                "If you did not make this change, please contact support immediately.",
                from_email=None,  # Uses DEFAULT_FROM_EMAIL
                recipient_list=[user.email],
                fail_silently=True,
            )
        except Exception:
            pass  # Don't fail the password change if email fails

    @classmethod
    def initiate_email_change(
        cls,
        user: "User",
        new_email: str,
        request: "HttpRequest | None" = None,
    ) -> dict:
        """
        Initiate an email change request.

        Args:
            user: The user requesting the change
            new_email: The new email address
            request: Optional request for context

        Returns:
            Dict with 'success' boolean and 'message' string
        """
        from apps.accounts.models import User

        # Validate email
        if not new_email or not new_email.strip():
            return {
                "success": False,
                "message": "Email address is required.",
            }

        new_email = new_email.strip().lower()

        # Check if email already in use
        if User.objects.filter(email=new_email).exclude(pk=user.pk).exists():
            return {
                "success": False,
                "message": "This email is already in use by another account.",
            }

        # Store pending email
        user.pending_email = new_email
        user.save(update_fields=["pending_email"])

        # Send verification email
        cls._send_email_verification(user, new_email, request)

        return {
            "success": True,
            "message": "Verification email sent. Please check your inbox.",
        }

    @classmethod
    def _send_email_verification(
        cls,
        user: "User",
        new_email: str,
        request: "HttpRequest | None" = None,
    ) -> None:
        """Send verification email for email change."""
        verification_code = secrets.token_urlsafe(32)

        # Store verification code (in production, use a proper token model)
        user.email_verification_code = verification_code
        user.save(update_fields=["email_verification_code"])

        try:
            send_mail(
                subject="Verify Your New Email - ThrillWiki",
                message=f"Hi {user.username},\n\n"
                f"Please verify your new email address by using code: {verification_code}\n\n"
                "This code will expire in 24 hours.",
                from_email=None,
                recipient_list=[new_email],
                fail_silently=True,
            )
        except Exception:
            pass
