"""
審計日誌服務
自動記錄所有 CRUD 操作,符合 ISO 要求
"""
from typing import Optional, Dict, Any
from datetime import datetime
from sqlalchemy.orm import Session
from fastapi import Request

from app.models.audit_log import AuditLog


class AuditService:
    """審計日誌服務類別"""

    @staticmethod
    def log(
        db: Session,
        action: str,
        resource_type: str,
        performed_by: str,
        resource_id: Optional[int] = None,
        details: Optional[Dict[str, Any]] = None,
        ip_address: Optional[str] = None,
    ) -> AuditLog:
        """
        創建審計日誌

        Args:
            db: 資料庫 Session
            action: 操作類型 (create/update/delete/login/logout)
            resource_type: 資源類型 (employee/identity/department/etc)
            performed_by: 操作者 SSO 帳號
            resource_id: 資源 ID
            details: 詳細變更內容 (dict)
            ip_address: IP 位址

        Returns:
            AuditLog: 創建的審計日誌物件
        """
        # TODO: 從 JWT token 或 session 獲取 tenant_id,目前暫時使用預設值 1
        tenant_id = 1

        audit_log = AuditLog(
            tenant_id=tenant_id,
            action=action,
            resource_type=resource_type,
            resource_id=resource_id,
            performed_by=performed_by,
            details=details,
            ip_address=ip_address,
        )

        db.add(audit_log)
        db.commit()
        db.refresh(audit_log)

        return audit_log

    @staticmethod
    def log_create(
        db: Session,
        resource_type: str,
        resource_id: int,
        performed_by: str,
        details: Dict[str, Any],
        ip_address: Optional[str] = None,
    ) -> AuditLog:
        """記錄創建操作"""
        return AuditService.log(
            db=db,
            action="create",
            resource_type=resource_type,
            resource_id=resource_id,
            performed_by=performed_by,
            details=details,
            ip_address=ip_address,
        )

    @staticmethod
    def log_update(
        db: Session,
        resource_type: str,
        resource_id: int,
        performed_by: str,
        old_values: Dict[str, Any],
        new_values: Dict[str, Any],
        ip_address: Optional[str] = None,
    ) -> AuditLog:
        """
        記錄更新操作

        Args:
            old_values: 舊值
            new_values: 新值
        """
        details = {
            "old": old_values,
            "new": new_values,
            "changed_fields": list(set(old_values.keys()) & set(new_values.keys()))
        }

        return AuditService.log(
            db=db,
            action="update",
            resource_type=resource_type,
            resource_id=resource_id,
            performed_by=performed_by,
            details=details,
            ip_address=ip_address,
        )

    @staticmethod
    def log_delete(
        db: Session,
        resource_type: str,
        resource_id: int,
        performed_by: str,
        details: Dict[str, Any],
        ip_address: Optional[str] = None,
    ) -> AuditLog:
        """記錄刪除操作"""
        return AuditService.log(
            db=db,
            action="delete",
            resource_type=resource_type,
            resource_id=resource_id,
            performed_by=performed_by,
            details=details,
            ip_address=ip_address,
        )

    @staticmethod
    def log_login(
        db: Session,
        username: str,
        ip_address: Optional[str] = None,
        success: bool = True,
    ) -> AuditLog:
        """記錄登入操作"""
        return AuditService.log(
            db=db,
            action="login",
            resource_type="authentication",
            performed_by=username,
            details={"success": success},
            ip_address=ip_address,
        )

    @staticmethod
    def log_logout(
        db: Session,
        username: str,
        ip_address: Optional[str] = None,
    ) -> AuditLog:
        """記錄登出操作"""
        return AuditService.log(
            db=db,
            action="logout",
            resource_type="authentication",
            performed_by=username,
            ip_address=ip_address,
        )

    @staticmethod
    def get_client_ip(request: Request) -> Optional[str]:
        """
        從 Request 獲取客戶端 IP

        優先順序:
        1. X-Forwarded-For (代理服務器)
        2. X-Real-IP (Nginx)
        3. request.client.host (直接連接)
        """
        # 檢查 X-Forwarded-For
        forwarded_for = request.headers.get("X-Forwarded-For")
        if forwarded_for:
            # 取第一個 IP (客戶端真實 IP)
            return forwarded_for.split(",")[0].strip()

        # 檢查 X-Real-IP
        real_ip = request.headers.get("X-Real-IP")
        if real_ip:
            return real_ip

        # 直接連接
        if request.client:
            return request.client.host

        return None

    @staticmethod
    def model_to_dict(obj, exclude_fields: Optional[set] = None) -> Dict[str, Any]:
        """
        將 SQLAlchemy Model 轉換為 dict (用於審計日誌)

        Args:
            obj: SQLAlchemy Model 物件
            exclude_fields: 排除的欄位集合

        Returns:
            dict: 模型的 dict 表示
        """
        if exclude_fields is None:
            exclude_fields = {"created_at", "updated_at", "_sa_instance_state"}

        result = {}
        for column in obj.__table__.columns:
            if column.name not in exclude_fields:
                value = getattr(obj, column.name)
                # 處理 datetime
                if isinstance(value, datetime):
                    value = value.isoformat()
                result[column.name] = value

        return result


    @staticmethod
    def log_action(
        db: Session,
        action: str,
        resource_type: str,
        resource_id: Optional[int] = None,
        details: Optional[Dict[str, Any]] = None,
        request: Optional[Request] = None,
        performed_by: str = "system",
    ) -> AuditLog:
        """
        通用操作記錄 (permissions.py 使用的介面)

        Args:
            db: 資料庫 Session
            action: 操作類型
            resource_type: 資源類型
            resource_id: 資源 ID
            details: 詳細內容
            request: FastAPI Request 物件 (用於取得 IP)
            performed_by: 操作者
        """
        ip_address = None
        if request is not None:
            ip_address = AuditService.get_client_ip(request)

        return AuditService.log(
            db=db,
            action=action,
            resource_type=resource_type,
            resource_id=resource_id,
            performed_by=performed_by,
            details=details,
            ip_address=ip_address,
        )


# 全域審計服務實例
audit_service = AuditService()
