import firebase_admin
from firebase_admin import credentials, messaging
import json
import os
import logging
from app.core.config import settings
import traceback

logger = logging.getLogger('adimsayar')

# Firebase Admin SDK 초기화 상태 추적
_firebase_initialized = False

def initialize_firebase():
    """
    Firebase Admin SDK를 초기화합니다.
    서비스 계정 키는 환경 변수 또는 파일에서 로드합니다.
    """
    global _firebase_initialized
    
    if _firebase_initialized:
        logger.info("Firebase already initialized, skipping initialization")
        return True
    
    try:
        logger.info("Attempting to initialize Firebase Admin SDK...")
        
        # 1. 환경 변수에서 서비스 계정 키 가져오기 시도
        firebase_credentials_json = os.environ.get('FIREBASE_SERVICE_ACCOUNT')
        
        if firebase_credentials_json:
            logger.info("Found Firebase credentials in environment variable")
            # 환경 변수에서 직접 JSON 로드
            try:
                cred_dict = json.loads(firebase_credentials_json)
                cred = credentials.Certificate(cred_dict)
                firebase_admin.initialize_app(cred)
                _firebase_initialized = True
                logger.info("Firebase Admin SDK initialized successfully from environment variable")
                return True
            except json.JSONDecodeError:
                logger.error("Failed to parse Firebase credentials from environment variable")
                logger.error(traceback.format_exc())
        
        # 2. 파일에서 서비스 계정 키 가져오기 시도
        # 기본 경로 및 여러 대체 경로 지정
        possible_paths = [
            os.environ.get('FIREBASE_SERVICE_ACCOUNT_PATH', 'app/firebase-service-account.json'),
            'app/firebase-service-account.json',
            '/app/app/firebase-service-account.json',
            '/var/www/adimsayar.easerver.net/htdocs/backend/app/firebase-service-account.json',
            'firebase-service-account.json'
        ]
        
        for firebase_credentials_path in possible_paths:
            logger.info(f"Looking for Firebase credentials file at: {firebase_credentials_path}")
            
            if os.path.exists(firebase_credentials_path) and os.path.isfile(firebase_credentials_path):
                try:
                    cred = credentials.Certificate(firebase_credentials_path)
                    firebase_admin.initialize_app(cred)
                    _firebase_initialized = True
                    logger.info(f"Firebase Admin SDK initialized successfully from file: {firebase_credentials_path}")
                    return True
                except Exception as e:
                    logger.error(f"Failed to initialize Firebase from credentials file {firebase_credentials_path}: {str(e)}")
                    logger.error(traceback.format_exc())
            else:
                if os.path.exists(firebase_credentials_path):
                    logger.warning(f"Path exists but is not a file: {firebase_credentials_path}")
                else:
                    logger.warning(f"Firebase credentials file not found at: {firebase_credentials_path}")
        
        # 3. Firebase 서비스 계정 JSON 수동 생성
        if all([settings.FIREBASE_PROJECT_ID, settings.FIREBASE_CLIENT_EMAIL, settings.FIREBASE_PRIVATE_KEY]):
            logger.info("Creating Firebase credentials from environment variables")
            cred_dict = {
                "type": "service_account",
                "project_id": settings.FIREBASE_PROJECT_ID,
                "private_key": settings.FIREBASE_PRIVATE_KEY,
                "client_email": settings.FIREBASE_CLIENT_EMAIL
            }
            try:
                cred = credentials.Certificate(cred_dict)
                firebase_admin.initialize_app(cred)
                _firebase_initialized = True
                logger.info("Firebase Admin SDK initialized successfully from environment variables")
                return True
            except Exception as e:
                logger.error(f"Failed to initialize Firebase from environment variables: {str(e)}")
                logger.error(traceback.format_exc())
        
        # 4. 기본 앱으로 초기화 시도 (GCP 환경에서 자동 인증)
        try:
            logger.info("Attempting to initialize Firebase with default app (GCP environment)")
            firebase_admin.initialize_app()
            _firebase_initialized = True
            logger.info("Firebase Admin SDK initialized successfully with default app")
            return True
        except Exception as e:
            logger.error(f"Failed to initialize Firebase with default app: {str(e)}")
            logger.error(traceback.format_exc())
    
    except Exception as e:
        logger.error(f"Firebase Admin SDK initialization failed: {str(e)}")
        logger.error(traceback.format_exc())
        # 초기화에 실패해도 앱은 계속 실행되도록 합니다.
        # Expo 푸시 알림은 여전히 작동할 것입니다.
    
    return False

def initialize_firebase_app():
    """
    Firebase Admin SDK를 초기화하고 Firebase 앱 객체를 반환합니다.
    서비스 계정 키는 환경 변수 또는 파일에서 로드합니다.
    
    Returns:
        Firebase 앱 객체 또는 오류 발생 시 None
    """
    global _firebase_initialized
    
    if _firebase_initialized:
        logger.info("Firebase already initialized, returning existing app")
        return firebase_admin.get_app()
    
    try:
        logger.info("Attempting to initialize Firebase Admin SDK...")
        
        # 1. 환경 변수에서 서비스 계정 키 가져오기 시도
        firebase_credentials_json = os.environ.get('FIREBASE_SERVICE_ACCOUNT')
        
        if firebase_credentials_json:
            logger.info("Found Firebase credentials in environment variable")
            # 환경 변수에서 직접 JSON 로드
            try:
                cred_dict = json.loads(firebase_credentials_json)
                cred = credentials.Certificate(cred_dict)
                app = firebase_admin.initialize_app(cred)
                _firebase_initialized = True
                logger.info("Firebase Admin SDK initialized successfully from environment variable")
                return app
            except json.JSONDecodeError:
                logger.error("Failed to parse Firebase credentials from environment variable")
                logger.error(traceback.format_exc())
        
        # 2. 파일에서 서비스 계정 키 가져오기 시도
        # 기본 경로 및 여러 대체 경로 지정
        possible_paths = [
            os.environ.get('FIREBASE_SERVICE_ACCOUNT_PATH', 'app/firebase-service-account.json'),
            'app/firebase-service-account.json',
            '/app/app/firebase-service-account.json',
            '/var/www/adimsayar.easerver.net/htdocs/backend/app/firebase-service-account.json',
            'firebase-service-account.json'
        ]
        
        for firebase_credentials_path in possible_paths:
            logger.info(f"Looking for Firebase credentials file at: {firebase_credentials_path}")
            
            if os.path.exists(firebase_credentials_path) and os.path.isfile(firebase_credentials_path):
                try:
                    cred = credentials.Certificate(firebase_credentials_path)
                    app = firebase_admin.initialize_app(cred)
                    _firebase_initialized = True
                    logger.info(f"Firebase Admin SDK initialized successfully from file: {firebase_credentials_path}")
                    return app
                except Exception as e:
                    logger.error(f"Failed to initialize Firebase from credentials file {firebase_credentials_path}: {str(e)}")
                    logger.error(traceback.format_exc())
            else:
                if os.path.exists(firebase_credentials_path):
                    logger.warning(f"Path exists but is not a file: {firebase_credentials_path}")
                else:
                    logger.warning(f"Firebase credentials file not found at: {firebase_credentials_path}")
        
        # 3. Firebase 서비스 계정 JSON 수동 생성
        if all([settings.FIREBASE_PROJECT_ID, settings.FIREBASE_CLIENT_EMAIL, settings.FIREBASE_PRIVATE_KEY]):
            logger.info("Creating Firebase credentials from environment variables")
            cred_dict = {
                "type": "service_account",
                "project_id": settings.FIREBASE_PROJECT_ID,
                "private_key": settings.FIREBASE_PRIVATE_KEY,
                "client_email": settings.FIREBASE_CLIENT_EMAIL
            }
            try:
                cred = credentials.Certificate(cred_dict)
                app = firebase_admin.initialize_app(cred)
                _firebase_initialized = True
                logger.info("Firebase Admin SDK initialized successfully from environment variables")
                return app
            except Exception as e:
                logger.error(f"Failed to initialize Firebase from environment variables: {str(e)}")
                logger.error(traceback.format_exc())
        
        # 4. 기본 앱으로 초기화 시도 (GCP 환경에서 자동 인증)
        try:
            logger.info("Attempting to initialize Firebase with default app (GCP environment)")
            app = firebase_admin.initialize_app()
            _firebase_initialized = True
            logger.info("Firebase Admin SDK initialized successfully with default app")
            return app
        except Exception as e:
            logger.error(f"Failed to initialize Firebase with default app: {str(e)}")
            logger.error(traceback.format_exc())
    
    except Exception as e:
        logger.error(f"Firebase Admin SDK initialization failed: {str(e)}")
        logger.error(traceback.format_exc())
    
    return None

def send_firebase_message(
    token: str,
    title: str,
    body: str,
    data: dict = None,
    notification_type: str = None,
    dry_run: bool = False
):
    """
    Firebase Cloud Messaging을 사용하여 단일 디바이스에 메시지를 보냅니다.
    
    Args:
        token: FCM 토큰
        title: 알림 제목
        body: 알림 내용
        data: 추가 데이터 페이로드
        notification_type: 알림 타입 (data에 자동으로 추가됨)
        dry_run: 실제로 메시지를 보내지 않고 검증만 수행 (테스트용)
    
    Returns:
        메시지 ID 또는 오류 발생 시 None
    """
    if not _firebase_initialized:
        logger.info("Firebase not initialized, attempting to initialize now")
        initialize_firebase()
        
        # 초기화가 실패한 경우
        if not _firebase_initialized:
            logger.error("Cannot send Firebase message: Firebase initialization failed")
            return None
    
    try:
        # 디버깅용 로깅 - 토큰 확인
        logger.info(f"Using FCM token (first 15 chars): {token[:15]}...")
        
        # data 딕셔너리 준비
        message_data = data.copy() if data else {}
        
        # notification_type이 제공되면 data에 추가
        if notification_type:
            message_data['type'] = notification_type
            
        # 모든 값을 문자열로 변환 (FCM 요구사항)
        string_data = {}
        for key, value in message_data.items():
            string_data[str(key)] = str(value)
        
        # FCM 페이로드 디버깅 로깅
        logger.info(f"Preparing FCM payload: title='{title}', body='{body}'")
        logger.info(f"Data payload: {json.dumps(string_data)}")
        
        # 안드로이드용 알림 구성 (콘솔과 동일한 형식)
        android_config = messaging.AndroidConfig(
            priority='high',
            notification=messaging.AndroidNotification(
                title=title,
                body=body,
                icon='ic_notification',
                color='#4285F4',
                channel_id='default',
                click_action='FLUTTER_NOTIFICATION_CLICK',  # 중요: Flutter/기본 앱 열기 설정
                tag=notification_type or 'general',
                sound='default'
            )
        )
        
        # iOS용 알림 구성 (콘솔과 동일한 형식)
        apns_config = messaging.APNSConfig(
            headers={'apns-priority': '10'},
            payload=messaging.APNSPayload(
                aps=messaging.Aps(
                    alert=messaging.ApsAlert(
                        title=title,
                        body=body
                    ),
                    badge=1,
                    sound='default',
                    category='MESSAGE',
                    content_available=True  # 백그라운드에서도 알림 처리 가능
                )
                # fcm_options 제거 - 직렬화 오류 해결
            )
        )
        
        # 웹 설정 추가
        webpush_config = messaging.WebpushConfig(
            notification=messaging.WebpushNotification(
                title=title,
                body=body,
                icon='https://adimsayar.easerver.net/favicon.ico'
            ),
            fcm_options=messaging.WebpushFCMOptions(
                link='https://adimsayar.easerver.net'
            )
        )
        
        # 메시지 구성
        message = messaging.Message(
            data=string_data,
            notification=messaging.Notification(
                title=title,
                body=body
            ),
            token=token,
            android=android_config,
            apns=apns_config,
            webpush=webpush_config
        )
        
        # Dry run 모드일 경우 로그
        if dry_run:
            logger.info(f"DRY RUN: Would send Firebase message to token: {token[:15]}...")
            return "dry-run-message-id"
        
        # 메시지 전송
        logger.info(f"Sending Firebase message to token: {token[:15]}...")
        response = messaging.send(message)
        logger.info(f"Firebase message sent successfully, message ID: {response}")
        return response
    
    except Exception as e:
        logger.error(f"Error sending Firebase message: {str(e)}")
        logger.error(traceback.format_exc())
        return None

def send_firebase_multicast(
    tokens: list,
    title: str,
    body: str,
    data: dict = None,
    notification_type: str = None,
    dry_run: bool = False
):
    """
    Firebase Cloud Messaging을 사용하여 여러 디바이스에 메시지를 보냅니다.
    
    Args:
        tokens: FCM 토큰 리스트 (최대 500개)
        title: 알림 제목
        body: 알림 내용
        data: 추가 데이터 페이로드
        notification_type: 알림 타입 (data에 자동으로 추가됨)
        dry_run: 실제로 메시지를 보내지 않고 검증만 수행 (테스트용)
    
    Returns:
        성공한 메시지 수와 실패한 메시지 수를 포함하는 튜플
    """
    if not tokens:
        logger.info("No tokens provided for Firebase multicast")
        return 0, 0
    
    if not _firebase_initialized:
        logger.info("Firebase not initialized, attempting to initialize now")
        initialize_firebase()
        
        # 초기화가 실패한 경우
        if not _firebase_initialized:
            logger.error("Cannot send Firebase multicast: Firebase initialization failed")
            return 0, len(tokens)
    
    try:
        # FCM 토큰은 배치로 처리해야 합니다(최대 500개)
        if len(tokens) > 500:
            logger.warning(f"Too many tokens ({len(tokens)}), limiting to 500")
            tokens = tokens[:500]
        
        logger.info(f"Preparing Firebase multicast to {len(tokens)} tokens")
        
        # data 딕셔너리 준비
        message_data = data.copy() if data else {}
        
        # notification_type이 제공되면 data에 추가
        if notification_type:
            message_data['type'] = notification_type
            
        # 모든 값을 문자열로 변환 (FCM 요구사항)
        string_data = {}
        for key, value in message_data.items():
            string_data[str(key)] = str(value)
        
        # FCM 페이로드 디버깅 로깅
        logger.info(f"Multicast FCM payload: title='{title}', body='{body}'")
        logger.info(f"Multicast data payload: {json.dumps(string_data)}")
        
        # 토큰이 적은 경우 (5개 이하) 또는 배치 모드가 실패한 경우 개별 전송으로 대체
        if len(tokens) <= 5:
            logger.info(f"Small number of tokens ({len(tokens)}), sending individually instead of batch")
            return send_individual_messages(tokens, title, body, string_data, dry_run)
            
        # 안드로이드용 알림 구성 (콘솔과 동일한 형식)
        android_config = messaging.AndroidConfig(
            priority='high',
            notification=messaging.AndroidNotification(
                title=title,
                body=body,
                icon='ic_notification',
                color='#4285F4',
                channel_id='default',
                click_action='FLUTTER_NOTIFICATION_CLICK',  # 중요: Flutter/기본 앱 열기 설정
                tag=notification_type or 'general',
                sound='default'
            )
        )
        
        # iOS용 알림 구성 (콘솔과 동일한 형식)
        apns_config = messaging.APNSConfig(
            headers={'apns-priority': '10'},
            payload=messaging.APNSPayload(
                aps=messaging.Aps(
                    alert=messaging.ApsAlert(
                        title=title,
                        body=body
                    ),
                    badge=1,
                    sound='default',
                    category='MESSAGE',
                    content_available=True  # 백그라운드에서도 알림 처리 가능
                )
                # fcm_options 제거 - 직렬화 오류 해결
            )
        )
        
        # 웹 설정 추가
        webpush_config = messaging.WebpushConfig(
            notification=messaging.WebpushNotification(
                title=title,
                body=body,
                icon='https://adimsayar.easerver.net/favicon.ico'
            ),
            fcm_options=messaging.WebpushFCMOptions(
                link='https://adimsayar.easerver.net'
            )
        )
        
        # 멀티캐스트 메시지 구성
        multicast_message = messaging.MulticastMessage(
            data=string_data,
            notification=messaging.Notification(
                title=title,
                body=body
            ),
            tokens=tokens,
            android=android_config,
            apns=apns_config,
            webpush=webpush_config
        )
        
        # Dry run 모드일 경우 로그
        if dry_run:
            logger.info(f"DRY RUN: Would send Firebase multicast to {len(tokens)} tokens")
            return len(tokens), 0
        
        try:
            # 메시지 전송
            logger.info(f"Sending Firebase multicast to {len(tokens)} tokens")
            response = messaging.send_multicast(multicast_message)
            logger.info(f"Firebase multicast sent: success={response.success_count}, failure={response.failure_count}")
            
            # 실패한 메시지에 대한 상세 정보 로깅
            if response.failure_count > 0:
                for idx, resp in enumerate(response.responses):
                    if not resp.success:
                        logger.error(f"Firebase message to token {tokens[idx][:15]}... failed: {resp.exception}")
            
            return response.success_count, response.failure_count
        except firebase_admin.exceptions.NotFoundError as e:
            logger.warning(f"Batch API failed with 404 error: {str(e)}. Falling back to individual messages")
            return send_individual_messages(tokens, title, body, string_data, dry_run)
        
    except Exception as e:
        logger.error(f"Error sending Firebase multicast: {str(e)}")
        logger.error(traceback.format_exc())
        
        # 배치 모드 실패 시 개별 메시지 전송으로 대체
        logger.info("Attempting to send messages individually as fallback")
        try:
            return send_individual_messages(tokens, title, body, string_data, dry_run)
        except Exception as e2:
            logger.error(f"Individual message fallback also failed: {str(e2)}")
            return 0, len(tokens)

def send_individual_messages(tokens, title, body, data, dry_run=False):
    """
    개별 메시지를 보내는 헬퍼 함수 (multicast 대체용)
    """
    success_count = 0
    failure_count = 0
    
    logger.info(f"Sending {len(tokens)} messages individually")
    
    # 안드로이드용 알림 구성 (콘솔과 동일한 형식)
    android_config = messaging.AndroidConfig(
        priority='high',
        notification=messaging.AndroidNotification(
            title=title,
            body=body,
            icon='ic_notification',
            color='#4285F4',
            channel_id='default',
            click_action='FLUTTER_NOTIFICATION_CLICK',
            sound='default'
        )
    )
    
    # iOS용 알림 구성 (콘솔과 동일한 형식)
    apns_config = messaging.APNSConfig(
        headers={'apns-priority': '10'},
        payload=messaging.APNSPayload(
            aps=messaging.Aps(
                alert=messaging.ApsAlert(
                    title=title,
                    body=body
                ),
                badge=1,
                sound='default',
                category='MESSAGE',
                content_available=True
            )
        )
    )
    
    for token in tokens:
        try:
            if dry_run:
                logger.info(f"DRY RUN: Would send message to {token[:15]}...")
                success_count += 1
                continue
                
            message = messaging.Message(
                data=data,
                notification=messaging.Notification(
                    title=title,
                    body=body
                ),
                token=token,
                android=android_config,
                apns=apns_config
            )
            
            response = messaging.send(message)
            logger.info(f"Message sent successfully to {token[:15]}...")
            success_count += 1
        except Exception as e:
            logger.error(f"Failed to send message to {token[:15]}...: {str(e)}")
            failure_count += 1
    
    logger.info(f"Individual messages summary: {success_count} success, {failure_count} failure")
    return success_count, failure_count 