from django.conf import settings
from django.contrib.auth import get_user_model
from django.contrib.auth.models import AbstractBaseUser
from django.utils.translation import gettext_lazy as _
from firebase_admin import auth
from rest_framework import exceptions
from rest_framework.authentication import BaseAuthentication

from django_firebase_auth.auth import (
    create_user,
    is_valid_jwt,
    provider_data_to_dict,
    timestamp_to_datetime,
)

# 설정 값 읽기
AUTHORIZATION_HEADER = getattr(settings, "AUTHORIZATION_HEADER", "Authorization")
AUTHORIZATION_HEADER_PREFIX = getattr(settings, "AUTHORIZATION_HEADER_PREFIX", "Bearer ")
COOKIE_NAME = getattr(settings, "COOKIE_NAME", None)

UserModel: AbstractBaseUser = get_user_model()


class TokenAuthentication(BaseAuthentication):
    def authenticate(self, request):
        # request에서 토큰 가져오기
        token = request.headers.get(AUTHORIZATION_HEADER)
        if COOKIE_NAME:
            token = token or request.COOKIES.get(COOKIE_NAME)

        if not token:
            return

        # 토큰 형식 검증
        token = token.replace(AUTHORIZATION_HEADER_PREFIX, "").strip()
        if not is_valid_jwt(token):
            msg = _("JWT token이 유효하지 않습니다.")
            raise exceptions.AuthenticationFailed(msg)

        return self.authenticate_credentials(request, token)

    def authenticate_credentials(self, request, token):
        try:
            # Firebase 토큰 검증
            try:
                decoded_token = auth.verify_id_token(token)
            except auth.ExpiredIdTokenError:
                # 토큰이 만료되었을 때 401 대신 403을 반환하여
                # 클라이언트가 토큰 갱신을 시도할 수 있도록 함
                msg = _("만료된 Firebase 토큰입니다. 토큰을 갱신해주세요.")
                raise exceptions.NotAuthenticated(msg)
            except auth.InvalidIdTokenError:
                msg = _("유효하지 않은 Firebase 토큰입니다.")
                raise exceptions.AuthenticationFailed(msg)

            user_record = auth.get_user(decoded_token["uid"])

            if user_record is None:
                msg = _("Firebase user 가 존재하지 않습니다.")
                raise exceptions.AuthenticationFailed(msg)

            # DB에 사용자 정보 조회 또는 생성
            user = None
            try:
                # 사용자 정보 조회
                user = UserModel.objects.get(uid=user_record.uid)

                # 변경이 필요한 필드만 업데이트
                updates = {}

                if user.email_verified != user_record.email_verified:
                    updates["email_verified"] = user_record.email_verified

                npd = provider_data_to_dict(user_record.provider_data)
                if user.provider_data != npd:
                    updates["provider_data"] = npd

                nll = timestamp_to_datetime(user_record.user_metadata.last_sign_in_timestamp)
                if user.last_login != nll:
                    updates["last_login"] = nll

                # 변경사항이 있을 때만 update() 호출
                if updates:
                    UserModel.objects.filter(uid=user.uid).update(**updates)

                user.refresh_from_db()
            except UserModel.DoesNotExist:
                user = create_user(user_record)

            if user is None:
                msg = _("사용자 정보를 찾을 수 없습니다.")
                raise exceptions.AuthenticationFailed(msg)

            if not user.is_active:
                msg = _("사용자가 활성화되지 않았습니다.")
                raise exceptions.AuthenticationFailed(msg)

            return (user, token)

        except Exception as e:
            msg = _(f"인증 처리 중 오류가 발생했습니다.: {e}")
            raise exceptions.AuthenticationFailed(msg)

    def authenticate_header(self, request):
        return None
