from typing import Annotated
from uuid import UUID
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from app.core.database import get_db
from app.core.audit import log_audit
from app.models.user import User
from app.models.account import Account
from app.models.feature_flag import FeatureFlag, PlanFeatureDefault, AccountFeatureOverride
from app.schemas.admin import (
    FeatureFlagCreate, FeatureFlagUpdate, FeatureFlagResponse, PlanDefaultEntry,
    PlanDefaultUpdate,
    AccountFeatureOverrideCreate, AccountFeatureOverrideResponse,
)
from app.api.deps import require_admin

router = APIRouter(prefix="/admin/feature-flags", tags=["admin-feature-flags"])


@router.get("", response_model=list[FeatureFlagResponse])
async def list_feature_flags(
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(require_admin)],
):
    """List all feature flags with plan defaults."""
    result = await db.execute(select(FeatureFlag).order_by(FeatureFlag.display_name))
    flags = result.scalars().all()

    responses = []
    for flag in flags:
        # Get plan defaults for this flag
        defaults_result = await db.execute(
            select(PlanFeatureDefault).where(PlanFeatureDefault.flag_id == flag.id)
        )
        defaults = defaults_result.scalars().all()

        responses.append(FeatureFlagResponse(
            id=flag.id,
            flag_key=flag.flag_key,
            display_name=flag.display_name,
            description=flag.description,
            plan_defaults=[PlanDefaultEntry(plan=d.plan, enabled=d.enabled) for d in defaults],
            created_at=flag.created_at,
        ))

    return responses


@router.post("", response_model=FeatureFlagResponse, status_code=status.HTTP_201_CREATED)
async def create_feature_flag(
    data: FeatureFlagCreate,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(require_admin)],
):
    """Create a new feature flag."""
    # Check uniqueness
    existing = await db.execute(select(FeatureFlag).where(FeatureFlag.flag_key == data.flag_key))
    if existing.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Flag key already exists")

    flag = FeatureFlag(flag_key=data.flag_key, display_name=data.display_name, description=data.description)
    db.add(flag)
    await log_audit(db, current_user.id, "feature_flag.create", "feature_flag", details={"flag_key": data.flag_key})
    await db.commit()
    await db.refresh(flag)

    return FeatureFlagResponse(
        id=flag.id, flag_key=flag.flag_key, display_name=flag.display_name,
        description=flag.description, plan_defaults=[], created_at=flag.created_at,
    )


@router.put("/plan-defaults")
async def update_plan_default(
    data: PlanDefaultUpdate,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(require_admin)],
):
    """Update a plan feature default (upsert)."""
    result = await db.execute(
        select(PlanFeatureDefault).where(
            PlanFeatureDefault.plan == data.plan,
            PlanFeatureDefault.flag_id == data.flag_id,
        )
    )
    existing = result.scalar_one_or_none()

    if existing:
        existing.enabled = data.enabled
    else:
        new_default = PlanFeatureDefault(plan=data.plan, flag_id=data.flag_id, enabled=data.enabled)
        db.add(new_default)

    await log_audit(db, current_user.id, "plan_default.update", "feature_flag", data.flag_id,
                    {"plan": data.plan, "enabled": data.enabled})
    await db.commit()
    return {"ok": True}


@router.put("/{flag_id}", response_model=FeatureFlagResponse)
async def update_feature_flag(
    flag_id: UUID,
    data: FeatureFlagUpdate,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(require_admin)],
):
    """Update a feature flag."""
    result = await db.execute(select(FeatureFlag).where(FeatureFlag.id == flag_id))
    flag = result.scalar_one_or_none()
    if not flag:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Feature flag not found")

    if data.display_name is not None:
        flag.display_name = data.display_name
    if data.description is not None:
        flag.description = data.description

    await log_audit(db, current_user.id, "feature_flag.update", "feature_flag", flag.id)
    await db.commit()
    await db.refresh(flag)

    defaults_result = await db.execute(select(PlanFeatureDefault).where(PlanFeatureDefault.flag_id == flag.id))
    defaults = defaults_result.scalars().all()

    return FeatureFlagResponse(
        id=flag.id, flag_key=flag.flag_key, display_name=flag.display_name,
        description=flag.description,
        plan_defaults=[PlanDefaultEntry(plan=d.plan, enabled=d.enabled) for d in defaults],
        created_at=flag.created_at,
    )


@router.delete("/{flag_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_feature_flag(
    flag_id: UUID,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(require_admin)],
):
    """Delete a feature flag (cascades to defaults and overrides)."""
    result = await db.execute(select(FeatureFlag).where(FeatureFlag.id == flag_id))
    flag = result.scalar_one_or_none()
    if not flag:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Feature flag not found")

    await log_audit(db, current_user.id, "feature_flag.delete", "feature_flag", flag.id,
                    {"flag_key": flag.flag_key})
    await db.delete(flag)
    await db.commit()


# --- Account Feature Overrides ---

@router.get("/account-overrides", response_model=list[AccountFeatureOverrideResponse])
async def list_account_feature_overrides(
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(require_admin)],
):
    """List all account feature overrides."""
    query = (
        select(
            AccountFeatureOverride,
            Account.display_code.label("account_display_code"),
            FeatureFlag.flag_key.label("flag_key"),
            FeatureFlag.display_name.label("flag_display_name"),
        )
        .outerjoin(Account, AccountFeatureOverride.account_id == Account.id)
        .outerjoin(FeatureFlag, AccountFeatureOverride.flag_id == FeatureFlag.id)
        .order_by(AccountFeatureOverride.created_at.desc())
    )
    result = await db.execute(query)
    rows = result.all()

    return [
        AccountFeatureOverrideResponse(
            id=row.AccountFeatureOverride.id,
            account_id=row.AccountFeatureOverride.account_id,
            account_display_code=row.account_display_code,
            flag_id=row.AccountFeatureOverride.flag_id,
            flag_key=row.flag_key,
            flag_display_name=row.flag_display_name,
            enabled=row.AccountFeatureOverride.enabled,
            note=row.AccountFeatureOverride.note,
            created_at=row.AccountFeatureOverride.created_at,
        )
        for row in rows
    ]


@router.post("/account-overrides", response_model=AccountFeatureOverrideResponse, status_code=status.HTTP_201_CREATED)
async def create_account_feature_override(
    data: AccountFeatureOverrideCreate,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(require_admin)],
):
    """Create an account feature override."""
    # Look up account
    result = await db.execute(select(Account).where(Account.display_code == data.account_display_code))
    account = result.scalar_one_or_none()
    if not account:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Account not found")

    # Look up flag
    result = await db.execute(select(FeatureFlag).where(FeatureFlag.id == data.flag_id))
    flag = result.scalar_one_or_none()
    if not flag:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Feature flag not found")

    # Check for existing
    existing = await db.execute(
        select(AccountFeatureOverride).where(
            AccountFeatureOverride.account_id == account.id,
            AccountFeatureOverride.flag_id == data.flag_id,
        )
    )
    if existing.scalar_one_or_none():
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Override already exists")

    override = AccountFeatureOverride(
        account_id=account.id, flag_id=data.flag_id, enabled=data.enabled,
        note=data.note, created_by_id=current_user.id,
    )
    db.add(override)
    await log_audit(db, current_user.id, "feature_override.create", "account", account.id,
                    {"flag_key": flag.flag_key, "enabled": data.enabled})
    await db.commit()
    await db.refresh(override)

    return AccountFeatureOverrideResponse(
        id=override.id, account_id=override.account_id, account_display_code=account.display_code,
        flag_id=override.flag_id, flag_key=flag.flag_key, flag_display_name=flag.display_name,
        enabled=override.enabled, note=override.note, created_at=override.created_at,
    )


@router.delete("/account-overrides/{override_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_account_feature_override(
    override_id: UUID,
    db: Annotated[AsyncSession, Depends(get_db)],
    current_user: Annotated[User, Depends(require_admin)],
):
    """Delete an account feature override."""
    result = await db.execute(select(AccountFeatureOverride).where(AccountFeatureOverride.id == override_id))
    override = result.scalar_one_or_none()
    if not override:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Override not found")

    await log_audit(db, current_user.id, "feature_override.delete", "account", override.account_id)
    await db.delete(override)
    await db.commit()
