"""Shopify App domain - HTTP routes."""
from __future__ import annotations

from typing import Optional
from uuid import UUID

from fastapi import APIRouter, Depends, Path
from sqlalchemy.ext.asyncio import AsyncSession

from src.core.database import get_db
from src.core.dependencies import require_active_billing_for_workspace_id
from src.core.exceptions import ForbiddenError, NotFoundError
from src.domain.auth.models import User
from src.domain.auth.router import get_current_user
from src.domain.projects.repository import ProjectRepository
from src.domain.shopify_apps.repository import (
    ShopifyAppConfigRepository,
    ShopifyAppFunctionRepository,
    ShopifyAppResourcesRepository,
)
from src.domain.shopify_apps.schemas import (
    ShopifyAppConfigResponse,
    ShopifyAppConfigUpdate,
    ShopifyAppFunctionCreate,
    ShopifyAppFunctionDetailResponse,
    ShopifyAppFunctionResponse,
    ShopifyAppFunctionUpdate,
    ShopifyAppInstallInstructions,
    ShopifyAppPreviewTokenResponse,
    ShopifyAppResourcesResponse,
)
from src.domain.shopify_apps.service import ShopifyAppService
from src.workers.enqueue import enqueue_shopify_app_rebuild

router = APIRouter(prefix="/api/workspaces/{workspace_id}/projects/{project_id}/shopify-app", tags=["shopify-app"])


def _svc(db: AsyncSession = Depends(get_db)) -> ShopifyAppService:
    return ShopifyAppService(
        config_repo=ShopifyAppConfigRepository(db),
        function_repo=ShopifyAppFunctionRepository(db),
    )


# ── Resources ─────────────────────────────────────────────────────────────────

@router.get("/resources", response_model=ShopifyAppResourcesResponse)
async def get_resources(
    workspace_id: UUID = Depends(require_active_billing_for_workspace_id),
    project_id: UUID = Path(...),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
):
    await _resolve_project(workspace_id, project_id, user, db)
    row = await ShopifyAppResourcesRepository(db).get(project_id)
    if not row:
        return ShopifyAppResourcesResponse(
            project_id=project_id,
            d1_database_id=None,
            d1_database_name=None,
            queue_name=None,
            r2_bucket_name=None,
            kv_namespace_id=None,
            kv_namespace_name=None,
            cloud_client_id=None,
            status="provisioning",
            last_error=None,
            provisioned_at=None,
        )
    return row


async def _resolve_project(
    workspace_id: UUID,
    project_id: UUID,
    user: User,
    db: AsyncSession,
) -> str:
    """Verify project belongs to workspace and is a shopify_app; returns project_ref."""
    proj = await ProjectRepository(db).get_by_id(project_id)
    if not proj or proj.workspace_id != workspace_id:
        raise NotFoundError("Project not found")
    if proj.type != "shopify_app":
        raise ForbiddenError()
    return proj.project_ref or ""


# ── Config ────────────────────────────────────────────────────────────────────

@router.get("/config", response_model=ShopifyAppConfigResponse)
async def get_config(
    workspace_id: UUID = Depends(require_active_billing_for_workspace_id),
    project_id: UUID = Path(...),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
    svc: ShopifyAppService = Depends(_svc),
):
    project_ref = await _resolve_project(workspace_id, project_id, user, db)
    return await svc.get_or_create_config(project_id, project_ref)


@router.put("/config", response_model=ShopifyAppConfigResponse)
async def update_config(
    body: ShopifyAppConfigUpdate,
    workspace_id: UUID = Depends(require_active_billing_for_workspace_id),
    project_id: UUID = Path(...),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
    svc: ShopifyAppService = Depends(_svc),
):
    project_ref = await _resolve_project(workspace_id, project_id, user, db)
    result = await svc.update_config(
        project_id,
        project_ref,
        shop_domain=body.shop_domain,
        access_token=body.access_token,
        webhook_secret=body.webhook_secret,
    )
    await db.commit()
    return result


# ── Preview token (dashboard SSO) ─────────────────────────────────────────────

@router.get("/preview-token", response_model=ShopifyAppPreviewTokenResponse)
async def get_preview_token(
    workspace_id: UUID = Depends(require_active_billing_for_workspace_id),
    project_id: UUID = Path(...),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
    svc: ShopifyAppService = Depends(_svc),
):
    project_ref = await _resolve_project(workspace_id, project_id, user, db)
    return await svc.get_preview_token(project_id, project_ref)


# ── Install instructions ───────────────────────────────────────────────────────

@router.get("/install-instructions", response_model=ShopifyAppInstallInstructions)
async def get_install_instructions(
    workspace_id: UUID = Depends(require_active_billing_for_workspace_id),
    project_id: UUID = Path(...),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
    svc: ShopifyAppService = Depends(_svc),
):
    await _resolve_project(workspace_id, project_id, user, db)
    return await svc.get_install_instructions(project_id)


# ── Functions ─────────────────────────────────────────────────────────────────

@router.get("/functions", response_model=list[ShopifyAppFunctionResponse])
async def list_functions(
    workspace_id: UUID = Depends(require_active_billing_for_workspace_id),
    project_id: UUID = Path(...),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
    svc: ShopifyAppService = Depends(_svc),
):
    await _resolve_project(workspace_id, project_id, user, db)
    return await svc.list_functions(project_id)


@router.post("/functions", response_model=ShopifyAppFunctionDetailResponse, status_code=201)
async def create_function(
    body: ShopifyAppFunctionCreate,
    workspace_id: UUID = Depends(require_active_billing_for_workspace_id),
    project_id: UUID = Path(...),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
    svc: ShopifyAppService = Depends(_svc),
):
    await _resolve_project(workspace_id, project_id, user, db)
    result = await svc.create_function(project_id, body)
    await db.commit()
    await enqueue_shopify_app_rebuild(str(project_id))
    return result


@router.get("/functions/{function_id}", response_model=ShopifyAppFunctionDetailResponse)
async def get_function(
    function_id: UUID,
    workspace_id: UUID = Depends(require_active_billing_for_workspace_id),
    project_id: UUID = Path(...),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
    svc: ShopifyAppService = Depends(_svc),
):
    await _resolve_project(workspace_id, project_id, user, db)
    return await svc.get_function(project_id, function_id)


@router.put("/functions/{function_id}", response_model=ShopifyAppFunctionDetailResponse)
async def update_function(
    function_id: UUID,
    body: ShopifyAppFunctionUpdate,
    workspace_id: UUID = Depends(require_active_billing_for_workspace_id),
    project_id: UUID = Path(...),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
    svc: ShopifyAppService = Depends(_svc),
):
    await _resolve_project(workspace_id, project_id, user, db)
    result = await svc.update_function(project_id, function_id, body)
    await db.commit()
    await enqueue_shopify_app_rebuild(str(project_id))
    return result


@router.delete("/functions/{function_id}", status_code=204)
async def delete_function(
    function_id: UUID,
    workspace_id: UUID = Depends(require_active_billing_for_workspace_id),
    project_id: UUID = Path(...),
    user: User = Depends(get_current_user),
    db: AsyncSession = Depends(get_db),
    svc: ShopifyAppService = Depends(_svc),
):
    await _resolve_project(workspace_id, project_id, user, db)
    await svc.delete_function(project_id, function_id)
    await db.commit()
    await enqueue_shopify_app_rebuild(str(project_id))
