"""
初始化系統 API Endpoints
"""
import os
from typing import Dict, Any, Optional
from fastapi import APIRouter, Depends, HTTPException, status, Request
from sqlalchemy.orm import Session
from pydantic import BaseModel, Field

from app.api import deps
from app.services.environment_checker import EnvironmentChecker
from app.services.installation_service import InstallationService
from app.models import Tenant, InstallationSession


router = APIRouter()


# ==================== Pydantic Schemas ====================

class DatabaseConfig(BaseModel):
    """資料庫連線設定"""
    host: str = Field(..., description="主機位址")
    port: int = Field(5432, description="Port")
    database: str = Field(..., description="資料庫名稱")
    user: str = Field(..., description="使用者帳號")
    password: str = Field(..., description="密碼")


class RedisConfig(BaseModel):
    """Redis 連線設定"""
    host: str = Field(..., description="主機位址")
    port: int = Field(6379, description="Port")
    password: Optional[str] = Field(None, description="密碼")
    db: int = Field(0, description="資料庫編號")


class KeycloakConfig(BaseModel):
    """Keycloak 連線設定"""
    url: str = Field(..., description="Keycloak URL")
    realm: str = Field(..., description="Realm 名稱")
    admin_username: str = Field(..., description="Admin 帳號")
    admin_password: str = Field(..., description="Admin 密碼")


class TenantInfoInput(BaseModel):
    """公司資訊輸入"""
    company_name: str
    company_name_en: Optional[str] = None
    tenant_code: str  # Keycloak Realm 名稱
    tenant_prefix: str  # 員工編號前綴
    tax_id: Optional[str] = None
    tel: Optional[str] = None
    add: Optional[str] = None
    domain_set: int = 2  # 郵件網域條件：1=組織網域，2=部門網域
    domain: Optional[str] = None  # 組織網域（domain_set=1 時使用）


class AdminSetupInput(BaseModel):
    """管理員設定輸入"""
    admin_legal_name: str
    admin_english_name: str
    admin_email: str
    admin_phone: Optional[str] = None
    password_method: str = Field("auto", description="auto 或 manual")
    manual_password: Optional[str] = None


class DepartmentSetupInput(BaseModel):
    """部門設定輸入"""
    department_code: str
    department_name: str
    department_name_en: Optional[str] = None
    email_domain: str
    depth: int = 0


# ==================== Phase 0: 系統狀態檢查 ====================

@router.get("/check-status")
async def check_system_status(db: Session = Depends(deps.get_db)):
    """
    檢查系統狀態（三階段：Initialization/Operational/Transition）

    Returns:
        current_phase: initialization | operational | transition
        is_initialized: True/False
        next_action: 建議的下一步操作
    """
    from app.models.installation import InstallationSystemStatus, InstallationEnvironmentConfig

    try:
        # 取得系統狀態記錄（應該只有一筆）
        system_status = db.query(InstallationSystemStatus).first()

        if not system_status:
            # 如果沒有記錄，建立一個初始狀態
            system_status = InstallationSystemStatus(
                current_phase="initialization",
                initialization_completed=False,
                is_locked=False
            )
            db.add(system_status)
            db.commit()
            db.refresh(system_status)

        # 檢查環境配置完成度
        required_categories = ["redis", "database", "keycloak"]
        configured_categories = db.query(InstallationEnvironmentConfig.config_category).filter(
            InstallationEnvironmentConfig.is_configured == True
        ).distinct().all()
        configured_categories = [cat[0] for cat in configured_categories]

        # 只計算必要類別中已完成的數量
        configured_required_count = sum(1 for cat in required_categories if cat in configured_categories)
        all_required_configured = all(cat in configured_categories for cat in required_categories)

        result = {
            "current_phase": system_status.current_phase,
            "is_initialized": system_status.initialization_completed and all_required_configured,
            "initialization_completed": system_status.initialization_completed,
            "configured_count": configured_required_count,
            "configured_categories": configured_categories,
            "missing_categories": [cat for cat in required_categories if cat not in configured_categories],
            "is_locked": system_status.is_locked,
        }

        # 根據當前階段決定 next_action
        if system_status.current_phase == "initialization":
            if all_required_configured:
                result["next_action"] = "complete_initialization"
                result["message"] = "環境配置完成，請繼續完成初始化流程"
            else:
                result["next_action"] = "continue_setup"
                result["message"] = "請繼續設定環境"

        elif system_status.current_phase == "operational":
            result["next_action"] = "health_check"
            result["message"] = "系統運作中，可進行健康檢查"
            result["last_health_check_at"] = system_status.last_health_check_at.isoformat() if system_status.last_health_check_at else None
            result["health_check_status"] = system_status.health_check_status

        elif system_status.current_phase == "transition":
            result["next_action"] = "consistency_check"
            result["message"] = "系統處於移轉階段，需進行一致性檢查"
            result["env_db_consistent"] = system_status.env_db_consistent
            result["inconsistencies"] = system_status.inconsistencies

        return result

    except Exception as e:
        # 如果無法連接資料庫或表不存在，視為未初始化
        import traceback
        return {
            "current_phase": "initialization",
            "is_initialized": False,
            "initialization_completed": False,
            "configured_count": 0,
            "configured_categories": [],
            "missing_categories": ["redis", "database", "keycloak"],
            "next_action": "start_initialization",
            "message": f"資料庫檢查失敗，請開始初始化: {str(e)}",
            "traceback": traceback.format_exc()
        }


@router.get("/health-check")
async def health_check():
    """
    完整的健康檢查（已初始化系統使用）

    Returns:
        所有環境組件的檢測結果
    """
    checker = EnvironmentChecker()
    report = checker.check_all()

    # 計算整體狀態
    statuses = [comp["status"] for comp in report["components"].values()]

    if all(s == "ok" for s in statuses):
        report["overall_status"] = "healthy"
    elif any(s == "error" for s in statuses):
        report["overall_status"] = "unhealthy"
    else:
        report["overall_status"] = "degraded"

    return report


# ==================== Phase 1: Redis 設定 ====================

@router.post("/test-redis")
async def test_redis_connection(config: RedisConfig):
    """
    測試 Redis 連線

    - 測試連線是否成功
    - 測試 PING 命令
    """
    checker = EnvironmentChecker()

    result = checker.test_redis_connection(
        host=config.host,
        port=config.port,
        password=config.password,
        db=config.db
    )

    if not result["success"]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=result["error"]
        )

    return result


@router.get("/get-config/{category}")
async def get_saved_config(category: str, db: Session = Depends(deps.get_db)):
    """
    讀取已儲存的環境配置

    - category: redis, database, keycloak
    - 回傳: 已儲存的配置資料 (敏感欄位會遮罩)
    """
    from app.models.installation import InstallationEnvironmentConfig

    configs = db.query(InstallationEnvironmentConfig).filter(
        InstallationEnvironmentConfig.config_category == category,
        InstallationEnvironmentConfig.is_configured == True
    ).all()

    if not configs:
        return {
            "configured": False,
            "config": {}
        }

    # 將配置轉換為字典
    config_dict = {}
    for cfg in configs:
        # 移除前綴 (例如 REDIS_HOST → host)
        # 先移除前綴，再轉小寫
        key = cfg.config_key.replace(f"{category.upper()}_", "").lower()

        # 敏感欄位不回傳實際值
        if cfg.is_sensitive:
            config_dict[key] = "****" if cfg.config_value else ""
        else:
            config_dict[key] = cfg.config_value

    return {
        "configured": True,
        "config": config_dict
    }


@router.post("/setup-redis")
async def setup_redis(config: RedisConfig, db: Session = Depends(deps.get_db)):
    """
    設定 Redis

    1. 測試連線
    2. 寫入 .env
    3. 寫入資料庫 (installation_environment_config)
    """
    from app.models.installation import InstallationEnvironmentConfig
    from datetime import datetime

    checker = EnvironmentChecker()

    # 1. 測試連線
    test_result = checker.test_redis_connection(
        host=config.host,
        port=config.port,
        password=config.password,
        db=config.db
    )

    if not test_result["success"]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=test_result["error"]
        )

    # 2. 寫入 .env
    update_env_file("REDIS_HOST", config.host)
    update_env_file("REDIS_PORT", str(config.port))
    if config.password:
        update_env_file("REDIS_PASSWORD", config.password)
    update_env_file("REDIS_DB", str(config.db))

    # 3. 寫入資料庫
    configs_to_save = [
        {"key": "REDIS_HOST", "value": config.host, "sensitive": False},
        {"key": "REDIS_PORT", "value": str(config.port), "sensitive": False},
        {"key": "REDIS_PASSWORD", "value": config.password or "", "sensitive": True},
        {"key": "REDIS_DB", "value": str(config.db), "sensitive": False},
    ]

    for cfg in configs_to_save:
        existing = db.query(InstallationEnvironmentConfig).filter(
            InstallationEnvironmentConfig.config_key == cfg["key"]
        ).first()

        if existing:
            existing.config_value = cfg["value"]
            existing.is_sensitive = cfg["sensitive"]
            existing.is_configured = True
            existing.configured_at = datetime.now()
            existing.updated_at = datetime.now()
        else:
            new_config = InstallationEnvironmentConfig(
                config_key=cfg["key"],
                config_value=cfg["value"],
                config_category="redis",
                is_sensitive=cfg["sensitive"],
                is_configured=True,
                configured_at=datetime.now()
            )
            db.add(new_config)

    db.commit()

    # 重新載入環境變數
    os.environ["REDIS_HOST"] = config.host
    os.environ["REDIS_PORT"] = str(config.port)
    if config.password:
        os.environ["REDIS_PASSWORD"] = config.password
    os.environ["REDIS_DB"] = str(config.db)

    return {
        "success": True,
        "message": "Redis 設定完成並已記錄至資料庫",
        "next_step": "setup_database"
    }


# ==================== Phase 2: 資料庫設定 ====================

@router.post("/test-database")
async def test_database_connection(config: DatabaseConfig):
    """
    測試資料庫連線

    - 測試連線是否成功
    - 不寫入任何設定
    """
    checker = EnvironmentChecker()

    result = checker.test_database_connection(
        host=config.host,
        port=config.port,
        database=config.database,
        user=config.user,
        password=config.password
    )

    if not result["success"]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=result["error"]
        )

    return result


@router.post("/setup-database")
async def setup_database(config: DatabaseConfig):
    """
    設定資料庫並執行初始化

    1. 測試連線
    2. 寫入 .env
    3. 執行 migrations
    4. 建立預設租戶
    """
    checker = EnvironmentChecker()

    # 1. 測試連線
    test_result = checker.test_database_connection(
        host=config.host,
        port=config.port,
        database=config.database,
        user=config.user,
        password=config.password
    )

    if not test_result["success"]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=test_result["error"]
        )

    # 2. 建立連線字串
    connection_string = (
        f"postgresql+psycopg2://{config.user}:{config.password}"
        f"@{config.host}:{config.port}/{config.database}"
    )

    # 3. 寫入 .env
    update_env_file("DATABASE_URL", connection_string)

    # 重新載入環境變數
    os.environ["DATABASE_URL"] = connection_string

    # 4. 執行 migrations
    try:
        run_alembic_migrations()
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"資料表建立失敗: {str(e)}"
        )

    # 5. 建立預設租戶（未初始化狀態）
    from app.db.session import get_session_local
    from app.models.installation import InstallationEnvironmentConfig
    from datetime import datetime

    SessionLocal = get_session_local()
    db = SessionLocal()
    try:
        existing_tenant = db.query(Tenant).first()
        if not existing_tenant:
            tenant = Tenant(
                code='temp',
                name='待設定',
                keycloak_realm='temp',
                is_initialized=False
            )
            db.add(tenant)
            db.commit()
            db.refresh(tenant)
            tenant_id = tenant.id
        else:
            tenant_id = existing_tenant.id

        # 6. 寫入資料庫配置記錄
        configs_to_save = [
            {"key": "DATABASE_URL", "value": connection_string, "sensitive": True},
            {"key": "DATABASE_HOST", "value": config.host, "sensitive": False},
            {"key": "DATABASE_PORT", "value": str(config.port), "sensitive": False},
            {"key": "DATABASE_NAME", "value": config.database, "sensitive": False},
            {"key": "DATABASE_USER", "value": config.user, "sensitive": False},
        ]

        for cfg in configs_to_save:
            existing = db.query(InstallationEnvironmentConfig).filter(
                InstallationEnvironmentConfig.config_key == cfg["key"]
            ).first()

            if existing:
                existing.config_value = cfg["value"]
                existing.is_sensitive = cfg["sensitive"]
                existing.is_configured = True
                existing.configured_at = datetime.now()
                existing.updated_at = datetime.now()
            else:
                new_config = InstallationEnvironmentConfig(
                    config_key=cfg["key"],
                    config_value=cfg["value"],
                    config_category="database",
                    is_sensitive=cfg["sensitive"],
                    is_configured=True,
                    configured_at=datetime.now()
                )
                db.add(new_config)

        db.commit()
    finally:
        db.close()

    return {
        "success": True,
        "message": "資料庫設定完成並已記錄",
        "tenant_id": tenant_id,
        "next_step": "setup_keycloak"
    }


# ==================== Phase 3: Keycloak 設定 ====================

@router.post("/test-keycloak")
async def test_keycloak_connection(config: KeycloakConfig):
    """
    測試 Keycloak 連線

    - 測試服務是否運行
    - 驗證管理員權限
    - 檢查 Realm 是否存在
    """
    checker = EnvironmentChecker()

    result = checker.test_keycloak_connection(
        url=config.url,
        realm=config.realm,
        admin_username=config.admin_username,
        admin_password=config.admin_password
    )

    if not result["success"]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=result["error"]
        )

    return result


@router.post("/setup-keycloak")
async def setup_keycloak(config: KeycloakConfig, db: Session = Depends(deps.get_db)):
    """
    設定 Keycloak

    1. 測試連線
    2. 寫入 .env
    3. 寫入資料庫
    4. 建立 Realm (如果不存在)
    5. 建立 Clients
    """
    from app.models.installation import InstallationEnvironmentConfig
    from datetime import datetime

    checker = EnvironmentChecker()

    # 1. 測試連線
    test_result = checker.test_keycloak_connection(
        url=config.url,
        realm=config.realm,
        admin_username=config.admin_username,
        admin_password=config.admin_password
    )

    if not test_result["success"]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=test_result["error"]
        )

    # 2. 寫入 .env
    update_env_file("KEYCLOAK_URL", config.url)
    update_env_file("KEYCLOAK_REALM", config.realm)
    update_env_file("KEYCLOAK_ADMIN_USERNAME", config.admin_username)
    update_env_file("KEYCLOAK_ADMIN_PASSWORD", config.admin_password)

    # 3. 寫入資料庫
    configs_to_save = [
        {"key": "KEYCLOAK_URL", "value": config.url, "sensitive": False},
        {"key": "KEYCLOAK_REALM", "value": config.realm, "sensitive": False},
        {"key": "KEYCLOAK_ADMIN_USERNAME", "value": config.admin_username, "sensitive": False},
        {"key": "KEYCLOAK_ADMIN_PASSWORD", "value": config.admin_password, "sensitive": True},
    ]

    for cfg in configs_to_save:
        existing = db.query(InstallationEnvironmentConfig).filter(
            InstallationEnvironmentConfig.config_key == cfg["key"]
        ).first()

        if existing:
            existing.config_value = cfg["value"]
            existing.is_sensitive = cfg["sensitive"]
            existing.is_configured = True
            existing.configured_at = datetime.now()
            existing.updated_at = datetime.now()
        else:
            new_config = InstallationEnvironmentConfig(
                config_key=cfg["key"],
                config_value=cfg["value"],
                config_category="keycloak",
                is_sensitive=cfg["sensitive"],
                is_configured=True,
                configured_at=datetime.now()
            )
            db.add(new_config)

    db.commit()

    # 重新載入環境變數
    os.environ["KEYCLOAK_URL"] = config.url
    os.environ["KEYCLOAK_REALM"] = config.realm

    # 4. 建立/驗證 Realm 和 Clients
    from app.services.keycloak_service import KeycloakService
    kc_service = KeycloakService()

    try:
        # 這裡可以加入自動建立 Realm 和 Clients 的邏輯
        # 目前先假設 Keycloak 已手動設定
        pass
    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Keycloak 設定失敗: {str(e)}"
        )

    return {
        "success": True,
        "message": "Keycloak 設定完成並已記錄",
        "realm_exists": test_result["realm_exists"],
        "next_step": "setup_company_info"
    }


# ==================== Phase 4: 公司資訊設定 ====================

@router.post("/sessions")
async def create_installation_session(
    environment: str = "production",
    db: Session = Depends(deps.get_db)
):
    """
    建立安裝會話

    - 開始初始化流程前必須先建立會話
    - 初始化時租戶尚未建立,所以 tenant_id 為 None
    """
    service = InstallationService(db)
    session = service.create_session(
        tenant_id=None,  # 初始化時還沒有租戶
        environment=environment,
        executed_by='installer'
    )

    return {
        "session_id": session.id,
        "tenant_id": session.tenant_id,
        "status": session.status
    }


@router.post("/sessions/{session_id}/tenant-info")
async def save_tenant_info(
    session_id: int,
    data: TenantInfoInput,
    db: Session = Depends(deps.get_db)
):
    """
    儲存公司資訊

    - 填寫完畢後即時儲存
    - 可重複呼叫更新
    """
    service = InstallationService(db)

    try:
        tenant_info = service.save_tenant_info(
            session_id=session_id,
            tenant_info_data=data.dict()
        )

        return {
            "success": True,
            "message": "公司資訊已儲存",
            "next_step": "setup_admin"
        }

    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=str(e)
        )


# ==================== Phase 5: 管理員設定 ====================

@router.post("/sessions/{session_id}/admin-setup")
async def setup_admin_credentials(
    session_id: int,
    data: AdminSetupInput,
    db: Session = Depends(deps.get_db)
):
    """
    設定系統管理員並產生初始密碼

    - 產生臨時密碼
    - 返回明文密碼（僅此一次）
    """
    service = InstallationService(db)

    try:
        # 預設資訊
        admin_data = {
            "admin_employee_id": "ADMIN001",
            "admin_username": "admin",
            "admin_legal_name": data.admin_legal_name,
            "admin_english_name": data.admin_english_name,
            "admin_email": data.admin_email,
            "admin_phone": data.admin_phone
        }

        tenant_info, initial_password = service.setup_admin_credentials(
            session_id=session_id,
            admin_data=admin_data,
            password_method=data.password_method,
            manual_password=data.manual_password
        )

        return {
            "success": True,
            "message": "管理員已設定",
            "username": "admin",
            "email": data.admin_email,
            "initial_password": initial_password,  # ⚠️ 僅返回一次
            "password_method": data.password_method,
            "next_step": "setup_departments"
        }

    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e)
        )


# ==================== Phase 6: 部門設定 ====================

@router.post("/sessions/{session_id}/departments")
async def setup_departments(
    session_id: int,
    departments: list[DepartmentSetupInput],
    db: Session = Depends(deps.get_db)
):
    """
    設定部門架構

    - 可一次設定多個部門
    """
    service = InstallationService(db)

    try:
        dept_setups = service.setup_departments(
            session_id=session_id,
            departments_data=[d.dict() for d in departments]
        )

        return {
            "success": True,
            "message": f"已設定 {len(dept_setups)} 個部門",
            "next_step": "execute_initialization"
        }

    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=str(e)
        )


# ==================== Phase 7: 執行初始化 ====================

@router.post("/sessions/{session_id}/execute")
async def execute_initialization(
    session_id: int,
    db: Session = Depends(deps.get_db)
):
    """
    執行完整的初始化流程

    1. 更新租戶資料
    2. 建立部門
    3. 建立管理員員工
    4. 建立 Keycloak 用戶
    5. 分配系統管理員角色
    6. 標記完成並鎖定
    """
    service = InstallationService(db)

    try:
        results = service.execute_initialization(session_id)

        return {
            "success": True,
            "message": "初始化完成",
            "results": results,
            "next_step": "redirect_to_login"
        }

    except Exception as e:
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=str(e)
        )


# ==================== 查詢與管理 ====================

@router.get("/sessions/{session_id}")
async def get_installation_session(
    session_id: int,
    db: Session = Depends(deps.get_db)
):
    """
    取得安裝會話詳細資訊

    - 如果已鎖定，敏感資訊將被隱藏
    """
    service = InstallationService(db)

    try:
        details = service.get_session_details(
            session_id=session_id,
            include_sensitive=False  # 預設不包含密碼
        )
        return details

    except ValueError as e:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail=str(e)
        )


@router.post("/sessions/{session_id}/clear-password")
async def clear_plain_password(
    session_id: int,
    db: Session = Depends(deps.get_db)
):
    """
    清除臨時密碼的明文

    - 使用者確認已複製密碼後呼叫
    """
    service = InstallationService(db)

    cleared = service.clear_plain_password(
        session_id=session_id,
        reason='user_confirmed'
    )

    return {
        "success": cleared,
        "message": "明文密碼已清除" if cleared else "找不到需要清除的密碼"
    }


# ==================== 輔助函數 ====================

def update_env_file(key: str, value: str):
    """
    更新 .env 檔案

    - 如果 key 已存在，更新值
    - 如果不存在，新增一行
    """
    env_path = os.path.join(os.getcwd(), '.env')

    # 讀取現有內容
    lines = []
    key_found = False

    if os.path.exists(env_path):
        with open(env_path, 'r', encoding='utf-8') as f:
            lines = f.readlines()

        # 更新現有 key
        for i, line in enumerate(lines):
            if line.startswith(f"{key}="):
                lines[i] = f"{key}={value}\n"
                key_found = True
                break

    # 如果 key 不存在，新增
    if not key_found:
        lines.append(f"{key}={value}\n")

    # 寫回檔案
    with open(env_path, 'w', encoding='utf-8') as f:
        f.writelines(lines)


def run_alembic_migrations():
    """
    執行 Alembic migrations

    - 使用 subprocess 呼叫 alembic upgrade head
    - Windows 環境下使用 Python 模組調用方式
    """
    import subprocess
    import sys

    try:
        result = subprocess.run(
            [sys.executable, '-m', 'alembic', 'upgrade', 'head'],
            cwd=os.getcwd(),
            capture_output=True,
            text=True,
            timeout=60
        )

        if result.returncode != 0:
            raise Exception(f"Alembic 執行失敗: {result.stderr}")

        return result.stdout

    except subprocess.TimeoutExpired:
        raise Exception("Alembic 執行逾時")
    except Exception as e:
        raise Exception(f"Alembic 執行錯誤: {str(e)}")


# ==================== 開發測試工具 ====================

@router.delete("/reset-config/{category}")
async def reset_environment_config(
    category: str,
    db: Session = Depends(deps.get_db)
):
    """
    重置環境配置（開發測試用）

    - category: redis, database, keycloak, 或 all
    - 刪除對應的配置記錄
    """
    from app.models.installation import InstallationEnvironmentConfig

    if category == "all":
        # 刪除所有配置
        db.query(InstallationEnvironmentConfig).delete()
        db.commit()
        return {"success": True, "message": "已重置所有環境配置"}
    else:
        # 刪除特定分類的配置
        deleted = db.query(InstallationEnvironmentConfig).filter(
            InstallationEnvironmentConfig.config_category == category
        ).delete()
        db.commit()

        if deleted > 0:
            return {"success": True, "message": f"已重置 {category} 配置 ({deleted} 筆記錄)"}
        else:
            return {"success": False, "message": f"找不到 {category} 的配置記錄"}


# ==================== 系統階段轉換 ====================

