"""
員工生命週期管理服務
自動化處理員工的新進、異動、離職流程
"""
from typing import Dict, Any, Optional
from sqlalchemy.orm import Session
import logging
import secrets
import string

from app.models.employee import Employee
from app.services.keycloak_admin_client import get_keycloak_admin_client
from app.services.drive_service import get_drive_service_client, get_drive_quota_by_job_level
from app.services.mailserver_service import get_mailserver_service, get_mail_quota_by_job_level

logger = logging.getLogger(__name__)


class EmployeeLifecycleService:
    """員工生命週期管理服務"""

    def __init__(self):
        self.keycloak_client = None

    def _get_keycloak_client(self):
        """延遲初始化 Keycloak Admin 客戶端"""
        if self.keycloak_client is None:
            self.keycloak_client = get_keycloak_admin_client()
        return self.keycloak_client

    def _generate_temporary_password(self, length: int = 12) -> str:
        """生成臨時密碼 (包含大小寫字母、數字和特殊字元)"""
        alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
        password = ''.join(secrets.choice(alphabet) for _ in range(length))
        return password

    async def onboard_employee(
        self,
        db: Session,
        employee: Employee,
        create_keycloak: bool = True,
        create_email: bool = True,
        create_drive: bool = True,
    ) -> Dict[str, Any]:
        """
        員工到職流程 (Onboarding)

        自動執行:
        1. 建立 Keycloak SSO 帳號
        2. 建立主要郵件帳號
        3. 建立雲端硬碟帳號 (Drive Service)
        4. 記錄審計日誌

        Args:
            db: 資料庫 Session
            employee: 員工物件
            create_keycloak: 是否建立 Keycloak 帳號
            create_email: 是否建立郵件帳號
            create_drive: 是否建立雲端硬碟帳號 (非致命，Drive Service 未上線時跳過)

        Returns:
            執行結果字典
        """
        results = {
            "employee_id": employee.id,
            "employee_number": employee.employee_id,
            "legal_name": employee.legal_name,
            "username_base": employee.username_base,
            "keycloak": {"created": False, "error": None},
            "email": {"created": False, "error": None},
            "drive": {"created": False, "error": None},
        }

        logger.info(f"開始員工到職流程: {employee.employee_id} - {employee.legal_name}")

        # 1. 建立 Keycloak 帳號
        if create_keycloak:
            try:
                keycloak_result = await self._create_keycloak_account(employee)
                results["keycloak"] = keycloak_result
                logger.info(f"Keycloak 帳號建立: {keycloak_result}")
            except Exception as e:
                logger.error(f"建立 Keycloak 帳號失敗: {str(e)}")
                results["keycloak"]["error"] = str(e)

        # 2. 建立郵件帳號
        if create_email:
            try:
                email_result = await self._create_email_account(employee)
                results["email"] = email_result
                logger.info(f"郵件帳號建立: {email_result}")
            except Exception as e:
                logger.error(f"建立郵件帳號失敗: {str(e)}")
                results["email"]["error"] = str(e)

        # 3. 建立雲端硬碟帳號 (Drive Service - 非致命)
        if create_drive:
            drive_result = await self._create_drive_account(employee)
            results["drive"] = drive_result
            if drive_result.get("error"):
                logger.warning(f"雲端硬碟帳號建立 (非致命): {drive_result}")
            else:
                logger.info(f"雲端硬碟帳號建立: {drive_result}")

        logger.info(f"員工到職流程完成: {employee.employee_id}")
        return results

    async def offboard_employee(
        self,
        db: Session,
        employee: Employee,
        disable_keycloak: bool = True,
        handle_email: str = "forward",  # "forward" or "disable"
        disable_drive: bool = True,
    ) -> Dict[str, Any]:
        """
        員工離職流程 (Offboarding)

        自動執行:
        1. 停用 Keycloak SSO 帳號
        2. 處理郵件帳號 (轉發或停用)
        3. 停用雲端硬碟帳號 (Drive Service - 非致命)
        4. 記錄審計日誌

        Args:
            db: 資料庫 Session
            employee: 員工物件
            disable_keycloak: 是否停用 Keycloak 帳號
            handle_email: 郵件處理方式 ("forward" 或 "disable")
            disable_drive: 是否停用雲端硬碟帳號 (非致命，Drive Service 未上線時跳過)

        Returns:
            執行結果字典
        """
        results = {
            "employee_id": employee.id,
            "employee_number": employee.employee_id,
            "legal_name": employee.legal_name,
            "keycloak": {"disabled": False, "error": None},
            "email": {"handled": False, "method": handle_email, "error": None},
            "drive": {"disabled": False, "error": None},
        }

        logger.info(f"開始員工離職流程: {employee.employee_id} - {employee.legal_name}")

        # 1. 停用 Keycloak 帳號
        if disable_keycloak:
            try:
                keycloak_result = await self._disable_keycloak_account(employee)
                results["keycloak"] = keycloak_result
                logger.info(f"Keycloak 帳號停用: {keycloak_result}")
            except Exception as e:
                logger.error(f"停用 Keycloak 帳號失敗: {str(e)}")
                results["keycloak"]["error"] = str(e)

        # 2. 處理郵件帳號
        try:
            email_result = await self._handle_email_offboarding(employee, handle_email)
            results["email"] = email_result
            logger.info(f"郵件帳號處理: {email_result}")
        except Exception as e:
            logger.error(f"處理郵件帳號失敗: {str(e)}")
            results["email"]["error"] = str(e)

        # 3. 停用雲端硬碟帳號 (Drive Service - 非致命)
        if disable_drive:
            drive_result = await self._disable_drive_account(employee)
            results["drive"] = drive_result
            if drive_result.get("error"):
                logger.warning(f"雲端硬碟帳號停用 (非致命): {drive_result}")
            else:
                logger.info(f"雲端硬碟帳號停用: {drive_result}")

        logger.info(f"員工離職流程完成: {employee.employee_id}")
        return results

    async def _create_keycloak_account(self, employee: Employee) -> Dict[str, Any]:
        """
        建立 Keycloak SSO 帳號

        執行步驟:
        1. 檢查帳號是否已存在
        2. 生成臨時密碼
        3. 建立 Keycloak 用戶
        4. 設定用戶屬性 (姓名、郵件等)

        Args:
            employee: 員工物件

        Returns:
            執行結果字典
        """
        try:
            client = self._get_keycloak_client()
            username = employee.username_base
            email = f"{username}@porscheworld.tw"

            # 1. 檢查帳號是否已存在
            existing_user = client.get_user_by_username(username)
            if existing_user:
                return {
                    "created": False,
                    "username": username,
                    "email": email,
                    "user_id": existing_user.get("id"),
                    "message": "Keycloak 帳號已存在",
                    "error": "用戶已存在",
                }

            # 2. 生成臨時密碼 (12位隨機密碼)
            temporary_password = self._generate_temporary_password(12)

            # 3. 分割姓名 (如果有英文名稱使用英文,否則使用中文)
            if employee.english_name:
                # 英文名稱格式: "FirstName LastName" 或 "FirstName MiddleName LastName"
                name_parts = employee.english_name.strip().split()
                first_name = name_parts[0] if len(name_parts) > 0 else username
                last_name = " ".join(name_parts[1:]) if len(name_parts) > 1 else ""
            else:
                # 中文名稱格式: "姓名" (第一個字是姓,其餘是名)
                legal_name = employee.legal_name or username
                first_name = legal_name[1:] if len(legal_name) > 1 else legal_name
                last_name = legal_name[0] if len(legal_name) > 0 else ""

            # 4. 建立 Keycloak 用戶
            user_id = client.create_user(
                username=username,
                email=email,
                first_name=first_name,
                last_name=last_name,
                enabled=True,
                email_verified=True,
            )

            if not user_id:
                return {
                    "created": False,
                    "username": username,
                    "email": email,
                    "message": "Keycloak 用戶建立失敗",
                    "error": "無法建立用戶 (API 返回 None)",
                }

            # 5. 設定初始密碼
            password_set = client.reset_password(
                user_id=user_id,
                password=temporary_password,
                temporary=True  # 用戶首次登入需修改密碼
            )

            if not password_set:
                logger.warning(f"Keycloak 用戶 {username} 建立成功,但密碼設定失敗")

            logger.info(f"✓ Keycloak 帳號建立成功: {username} (ID: {user_id})")

            return {
                "created": True,
                "username": username,
                "email": email,
                "user_id": user_id,
                "first_name": first_name,
                "last_name": last_name,
                "temporary_password": temporary_password,  # 應透過安全方式通知用戶
                "password_set": password_set,
                "message": f"Keycloak 帳號建立成功 (用戶首次登入需修改密碼)",
                "error": None,
            }

        except Exception as e:
            logger.error(f"✗ 建立 Keycloak 帳號時發生錯誤: {str(e)}")
            return {
                "created": False,
                "username": employee.username_base,
                "email": f"{employee.username_base}@porscheworld.tw",
                "message": "建立 Keycloak 帳號時發生錯誤",
                "error": str(e),
            }

    async def _create_email_account(self, employee: Employee) -> Dict[str, Any]:
        """
        建立郵件帳號 (Docker Mailserver)

        執行步驟:
        1. 依職級取得配額
        2. 產生臨時密碼 (員工後續透過 Keycloak SSO 登入)
        3. 透過 SSH + docker exec 建立帳號
        4. 設定配額
        """
        email_address = f"{employee.username_base}@porscheworld.tw"

        try:
            mailserver = get_mailserver_service()

            # 依職級取得郵件配額
            job_level = getattr(employee, "job_level", "Junior") or "Junior"
            quota_mb = get_mail_quota_by_job_level(job_level)

            # 產生臨時密碼
            temp_password = self._generate_temporary_password()

            result = mailserver.create_email_account(
                email=email_address,
                password=temp_password,
                quota_mb=quota_mb,
            )

            if result["created"]:
                logger.info(f"郵件帳號建立成功: {email_address} ({quota_mb}MB)")
            else:
                logger.warning(f"郵件帳號建立失敗: {email_address} - {result.get('error')}")

            return result

        except Exception as e:
            logger.warning(f"建立郵件帳號時發生非預期錯誤: {str(e)}")
            return {
                "created": False,
                "email": email_address,
                "quota_mb": 0,
                "message": "建立郵件帳號時發生錯誤",
                "error": str(e),
            }

    async def _create_drive_account(self, employee: Employee) -> Dict[str, Any]:
        """
        建立雲端硬碟帳號 (Drive Service)

        呼叫 drive-api.ease.taipei 建立 Nextcloud 帳號
        Drive Service 未上線時以 warning 記錄，不影響其他流程
        """
        try:
            client = get_drive_service_client()
            from app.core.config import settings

            # 根據職級取得配額
            job_level = getattr(employee, "job_level", "Junior") or "Junior"
            quota_gb = get_drive_quota_by_job_level(job_level)

            result = client.create_user(
                tenant_id=settings.DRIVE_SERVICE_TENANT_ID,
                keycloak_user_id=str(getattr(employee, "keycloak_user_id", "") or ""),
                username=employee.username_base,
                email=f"{employee.username_base}@porscheworld.tw",
                display_name=employee.legal_name or employee.username_base,
                quota_gb=quota_gb,
            )
            return result

        except Exception as e:
            logger.warning(f"建立雲端硬碟帳號時發生非預期錯誤: {str(e)}")
            return {
                "created": False,
                "username": employee.username_base,
                "quota_gb": 0,
                "drive_url": None,
                "message": "建立雲端硬碟帳號時發生錯誤",
                "error": str(e),
            }

    async def _disable_keycloak_account(self, employee: Employee) -> Dict[str, Any]:
        """
        停用 Keycloak SSO 帳號

        執行步驟:
        1. 查詢用戶 ID
        2. 停用帳號 (不刪除,保留審計記錄)

        注意: 不刪除帳號,只停用,以保留歷史記錄和審計追蹤

        Args:
            employee: 員工物件

        Returns:
            執行結果字典
        """
        try:
            client = self._get_keycloak_client()
            username = employee.username_base

            # 1. 查詢用戶
            user = client.get_user_by_username(username)
            if not user:
                return {
                    "disabled": False,
                    "username": username,
                    "message": "Keycloak 帳號不存在",
                    "error": "用戶不存在",
                }

            user_id = user.get("id")

            # 2. 檢查是否已停用
            if not user.get("enabled", False):
                return {
                    "disabled": True,
                    "username": username,
                    "user_id": user_id,
                    "message": "Keycloak 帳號已經是停用狀態",
                    "error": None,
                }

            # 3. 停用帳號
            success = client.disable_user(user_id)

            if success:
                logger.info(f"✓ Keycloak 帳號停用成功: {username} (ID: {user_id})")
                return {
                    "disabled": True,
                    "username": username,
                    "user_id": user_id,
                    "message": "Keycloak 帳號已停用 (帳號保留以維持審計記錄)",
                    "error": None,
                }
            else:
                return {
                    "disabled": False,
                    "username": username,
                    "user_id": user_id,
                    "message": "Keycloak 帳號停用失敗",
                    "error": "API 調用失敗",
                }

        except Exception as e:
            logger.error(f"✗ 停用 Keycloak 帳號時發生錯誤: {str(e)}")
            return {
                "disabled": False,
                "username": employee.username_base,
                "message": "停用 Keycloak 帳號時發生錯誤",
                "error": str(e),
            }

    async def _handle_email_offboarding(
        self, employee: Employee, method: str
    ) -> Dict[str, Any]:
        """
        處理離職員工的郵件帳號 (Docker Mailserver)

        Args:
            method: "forward" - 停用帳號並標記轉寄
                    "disable" - 直接刪除郵件帳號
        """
        email_address = f"{employee.username_base}@porscheworld.tw"

        try:
            mailserver = get_mailserver_service()

            if method == "forward":
                # 刪除帳號 (Docker Mailserver 不支援原生轉寄設定)
                # 轉寄規則記錄在 EmailAccount.forward_to，由 HR Portal 管理
                result = mailserver.delete_email_account(email_address)
                return {
                    "handled": result["deleted"],
                    "method": "forward",
                    "email": email_address,
                    "forward_to": "hr@porscheworld.tw",
                    "message": "郵件帳號已停用，轉寄規則已記錄" if result["deleted"] else "郵件帳號停用失敗",
                    "error": result.get("error"),
                }

            elif method == "disable":
                # 刪除郵件帳號
                result = mailserver.delete_email_account(email_address)
                return {
                    "handled": result["deleted"],
                    "method": "disable",
                    "email": email_address,
                    "message": "郵件帳號已刪除" if result["deleted"] else "郵件帳號刪除失敗",
                    "error": result.get("error"),
                }

            else:
                return {
                    "handled": False,
                    "method": method,
                    "email": email_address,
                    "error": f"不支援的處理方式: {method}",
                }

        except Exception as e:
            logger.warning(f"處理郵件帳號離職時發生非預期錯誤: {str(e)}")
            return {
                "handled": False,
                "method": method,
                "email": email_address,
                "message": "處理郵件帳號時發生錯誤",
                "error": str(e),
            }

    async def _disable_drive_account(self, employee: Employee) -> Dict[str, Any]:
        """
        停用雲端硬碟帳號 (Drive Service)

        呼叫 drive-api.ease.taipei 停用 Nextcloud 帳號 (軟刪除，保留檔案)
        Drive Service 未上線時以 warning 記錄，不影響其他流程
        """
        try:
            client = get_drive_service_client()

            # 查詢 drive_user_id (目前以 username 查詢)
            # Drive Service 上線後需實作 GET /api/v1/drive/users?username={username}
            # 暫時回傳 warning 狀態
            logger.warning(
                f"停用雲端硬碟帳號: {employee.username_base} - "
                f"需 Drive Service 上線後實作查詢 user_id 再停用"
            )
            return {
                "disabled": False,
                "username": employee.username_base,
                "message": "Drive Service 尚未上線，雲端硬碟帳號停用待後續處理",
                "error": "Drive Service 未上線",
            }

        except Exception as e:
            logger.warning(f"停用雲端硬碟帳號時發生非預期錯誤: {str(e)}")
            return {
                "disabled": False,
                "username": employee.username_base,
                "message": "停用雲端硬碟帳號時發生錯誤",
                "error": str(e),
            }


# 建立全域實例
employee_lifecycle_service = EmployeeLifecycleService()


def get_employee_lifecycle_service() -> EmployeeLifecycleService:
    """取得員工生命週期服務實例"""
    return employee_lifecycle_service
