# app/services/notification_service.py
from typing import List, Optional, Dict, Any
from sqlalchemy.orm import Session
from app.models.notification import Notification
from app.schemas.notification import NotificationResponse
import logging
from datetime import datetime
from zoneinfo import ZoneInfo
from fastapi import HTTPException
from sqlalchemy import text
import json

logger = logging.getLogger('adimsayar')

class NotificationService:
    @staticmethod
    def get_notifications(db: Session, user_id: int) -> List[NotificationResponse]:
        """
        사용자의 알림을 조회합니다 (소프트 삭제된 알림은 제외)
        """
        # data 필드에서 'deleted': true가 있는 알림 제외
        notifications = db.query(Notification).filter(
            Notification.user_id == user_id,
            # MySQL 호환 쿼리: data 필드가 NULL이거나 deleted:true가 없는 경우만 선택
            text("(data IS NULL OR JSON_EXTRACT(data, '$.deleted') IS NULL OR JSON_EXTRACT(data, '$.deleted') = 'false')")
        ).all()
        
        logger.info(f"get_notifications: found {len(notifications)} notifications for user_id {user_id}")
        # 디버깅용 로깅 추가
        for n in notifications:
            logger.debug(f"Notification id: {n.id}, data: {n.data}")
        
        return [NotificationResponse.from_orm(notification) for notification in notifications]

    @staticmethod
    def mark_notification_as_read(db: Session, notification_id: int, user_id: int) -> Optional[Notification]:
        # Filter to update only notifications owned by the user.
        notification = db.query(Notification).filter(
            Notification.id == notification_id,
            Notification.user_id == user_id
        ).first()
        if notification is None:
            logger.warning(f"Notification with id {notification_id} not found or not authorized for user_id {user_id}")
            return None
        notification.read_at = datetime.now(ZoneInfo("Europe/Istanbul"))
        db.commit()
        db.refresh(notification)
        logger.info(f"Notification id {notification_id} marked as read for user_id {user_id}")
        return notification

    @staticmethod
    def create_notification(db: Session, user_id: int, notif_type: str, title: str, message: str, data: Dict[str, Any] = None) -> Notification:
        """
        알림을 생성하고 데이터베이스에 추가합니다. 
        주의: 이 메서드는 db.commit()을 호출하지 않으므로, 호출하는 쪽에서 처리해야 합니다.
        
        푸시 알림 기능을 위해 호출하는 쪽에서 선택적으로 커밋을 제어할 수 있도록 설계되었습니다.
        """
        new_notification = Notification(
            user_id=user_id,
            type=notif_type,
            title=title,
            message=message,
            data=data
        )
        db.add(new_notification)
        return new_notification

    @staticmethod
    def send_notification(db: Session, user_id: int, title: str, message: str, notif_type: str = "general", data: Dict[str, Any] = None, send_push: bool = True):
        """
        알림을 생성하고 데이터베이스에 저장하며, 선택적으로 푸시 알림을 발송합니다.
        """
        # 알림 생성 및 저장
        new_notification = Notification(
            user_id=user_id,
            type=notif_type,
            title=title,
            message=message,
            data=data
        )
        db.add(new_notification)
        db.commit()
        db.refresh(new_notification)
        
        logger.info(f"New notification saved to database for user_id {user_id} with ID {new_notification.id}")
        
        # 푸시 알림 전송 (옵션이 활성화된 경우)
        if send_push:
            from app.services.expo_push_notification_service import ExpoPushNotificationService
            ExpoPushNotificationService.send_push_to_user(
                db=db,
                user_id=user_id,
                title=title,
                message=message,
                data=data,
                notification_type=notif_type,
                save_to_db=False  # 이미 DB에 저장했으므로 중복 저장 방지
            )
        
        return new_notification

    @staticmethod
    def send_welcome_notification(db: Session, user_id: int):
        """사용자 로그인 시 환영 메시지 전송"""
        logger.debug(f"New Client Login – Welcome Message Sent")
        return NotificationService.send_notification(
            db=db,
            user_id=user_id,
            title="Hoş geldiniz!",
            message="Adimsayar'a hoş geldiniz. İyi vakit geçirmenizi dileriz!",
            notif_type="hoş_geliş"
        )

    @staticmethod
    def soft_delete_notification(db: Session, notification_id: int, user_id: int) -> Optional[Notification]:
        """
        알림을 소프트 삭제합니다 (MySQL JSON 필드 직접 업데이트)
        """
        # 상세 로깅 추가
        logger.info(f"Attempting to soft delete notification {notification_id} for user {user_id}")
        
        # 먼저 알림이 존재하고 해당 사용자의 것인지 확인
        notification = db.query(Notification).filter(
            Notification.id == notification_id,
            Notification.user_id == user_id
        ).first()
        
        if notification is None:
            logger.warning(f"Notification with id {notification_id} not found or not authorized for user_id {user_id}")
            return None
        
        # 기존 data 가져오기
        current_data = notification.data or {}
        logger.info(f"Current data before update: {current_data}")
        
        # 현재 시간 (ISO 형식)
        deleted_at = datetime.now().isoformat()
        
        # 기존 data에 삭제 정보 추가
        current_data["deleted"] = True
        current_data["deleted_at"] = deleted_at
        
        # JSON 문자열로 변환
        json_data = json.dumps(current_data)
        
        try:
            # MySQL JSON_SET 함수를 사용하여 data 필드 업데이트
            # 직접 원시 SQL 쿼리 실행
            result = db.execute(
                text("""
                    UPDATE notifications 
                    SET data = :json_data 
                    WHERE id = :notification_id AND user_id = :user_id
                """), 
                {
                    "json_data": json_data,
                    "notification_id": notification_id,
                    "user_id": user_id
                }
            )
            
            # 커밋
            db.commit()
            
            logger.info(f"Update result: {result.rowcount} rows affected")
            
            # 변경사항 확인을 위해 다시 조회
            updated_notification = db.query(Notification).filter(
                Notification.id == notification_id
            ).first()
            
            logger.info(f"Updated notification data: {updated_notification.data}")
            
            return updated_notification
            
        except Exception as e:
            db.rollback()
            logger.error(f"Error updating notification data: {str(e)}", exc_info=True)
            raise