from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import selectinload

from app.api.deps import get_admin_user, get_db
from app.core.models.product import Product
from app.core.models.user import User
from app.core.services.plugin_helper import require_plugin
from app.plugins.product_media_roles.models import ProductMediaRole, ProductMediaRoleItem
from app.plugins.product_media_roles.schemas import (
    MediaRoleIn,
    MediaRoleOut,
    ProductMediaRoleItemIn,
    ProductMediaRoleItemOut,
)


async def _require_plugin(db: AsyncSession = Depends(get_db)) -> None:
    await require_plugin("product_media_roles", db)


router = APIRouter(tags=["product_media_roles"], dependencies=[Depends(_require_plugin)])


def _item_out(row: ProductMediaRoleItem) -> ProductMediaRoleItemOut:
    role = row.role
    return ProductMediaRoleItemOut(
        id=row.id,
        tenant_id=row.tenant_id,
        product_id=row.product_id,
        role_id=row.role_id,
        image_url=row.image_url,
        alt_text=row.alt_text,
        sort_order=row.sort_order,
        is_active=bool(row.is_active),
        role_code=role.code if role else None,
        role_label=role.label if role else None,
    )


async def _ensure_product(db: AsyncSession, tenant_id: int, product_id: int) -> Product:
    result = await db.execute(select(Product).where(Product.id == product_id, Product.tenant_id == tenant_id))
    product = result.scalar_one_or_none()
    if product is None:
        raise HTTPException(status_code=404, detail="Product not found")
    return product


@router.get("/product-media-roles", response_model=list[MediaRoleOut])
async def list_media_roles(
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(ProductMediaRole)
        .where(ProductMediaRole.tenant_id == user.tenant_id)
        .order_by(ProductMediaRole.sort_order, ProductMediaRole.id)
    )
    return result.scalars().all()


@router.post("/product-media-roles", response_model=MediaRoleOut, status_code=status.HTTP_201_CREATED)
async def create_media_role(
    body: MediaRoleIn,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_admin_user),
):
    row = ProductMediaRole(
        tenant_id=user.tenant_id,
        code=body.code,
        label=body.label,
        description=body.description,
        sort_order=body.sort_order,
        is_active=1 if body.is_active else 0,
    )
    db.add(row)
    await db.commit()
    await db.refresh(row)
    return row


@router.put("/product-media-roles/{role_id}", response_model=MediaRoleOut)
async def update_media_role(
    role_id: int,
    body: MediaRoleIn,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(ProductMediaRole).where(ProductMediaRole.id == role_id, ProductMediaRole.tenant_id == user.tenant_id)
    )
    row = result.scalar_one_or_none()
    if row is None:
        raise HTTPException(status_code=404, detail="Media role not found")
    row.code = body.code
    row.label = body.label
    row.description = body.description
    row.sort_order = body.sort_order
    row.is_active = 1 if body.is_active else 0
    await db.commit()
    await db.refresh(row)
    return row


@router.delete("/product-media-roles/{role_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_media_role(
    role_id: int,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(ProductMediaRole).where(ProductMediaRole.id == role_id, ProductMediaRole.tenant_id == user.tenant_id)
    )
    row = result.scalar_one_or_none()
    if row is None:
        raise HTTPException(status_code=404, detail="Media role not found")
    await db.delete(row)
    await db.commit()


@router.get("/products/{product_id}/media-role-items", response_model=list[ProductMediaRoleItemOut])
async def list_product_media_role_items(
    product_id: int,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_admin_user),
):
    await _ensure_product(db, user.tenant_id, product_id)
    result = await db.execute(
        select(ProductMediaRoleItem)
        .options(selectinload(ProductMediaRoleItem.role))
        .join(ProductMediaRole, ProductMediaRoleItem.role_id == ProductMediaRole.id)
        .where(
            ProductMediaRoleItem.tenant_id == user.tenant_id,
            ProductMediaRoleItem.product_id == product_id,
        )
        .order_by(ProductMediaRoleItem.sort_order, ProductMediaRoleItem.id)
    )
    return [_item_out(row) for row in result.scalars().all()]


@router.post("/products/{product_id}/media-role-items", response_model=ProductMediaRoleItemOut, status_code=status.HTTP_201_CREATED)
async def create_product_media_role_item(
    product_id: int,
    body: ProductMediaRoleItemIn,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_admin_user),
):
    await _ensure_product(db, user.tenant_id, product_id)
    role_result = await db.execute(
        select(ProductMediaRole).where(ProductMediaRole.id == body.role_id, ProductMediaRole.tenant_id == user.tenant_id)
    )
    role = role_result.scalar_one_or_none()
    if role is None:
        raise HTTPException(status_code=404, detail="Media role not found")
    row = ProductMediaRoleItem(
        tenant_id=user.tenant_id,
        product_id=product_id,
        role_id=body.role_id,
        image_url=body.image_url,
        alt_text=body.alt_text,
        sort_order=body.sort_order,
        is_active=1 if body.is_active else 0,
    )
    row.role = role
    db.add(row)
    await db.commit()
    await db.refresh(row)
    row.role = role
    return _item_out(row)


@router.put("/product-media-role-items/{item_id}", response_model=ProductMediaRoleItemOut)
async def update_product_media_role_item(
    item_id: int,
    body: ProductMediaRoleItemIn,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(ProductMediaRoleItem).where(ProductMediaRoleItem.id == item_id, ProductMediaRoleItem.tenant_id == user.tenant_id)
    )
    row = result.scalar_one_or_none()
    if row is None:
        raise HTTPException(status_code=404, detail="Media role item not found")
    role_result = await db.execute(
        select(ProductMediaRole).where(ProductMediaRole.id == body.role_id, ProductMediaRole.tenant_id == user.tenant_id)
    )
    role = role_result.scalar_one_or_none()
    if role is None:
        raise HTTPException(status_code=404, detail="Media role not found")
    row.role_id = body.role_id
    row.image_url = body.image_url
    row.alt_text = body.alt_text
    row.sort_order = body.sort_order
    row.is_active = 1 if body.is_active else 0
    row.role = role
    await db.commit()
    await db.refresh(row)
    row.role = role
    return _item_out(row)


@router.delete("/product-media-role-items/{item_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_product_media_role_item(
    item_id: int,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(ProductMediaRoleItem).where(ProductMediaRoleItem.id == item_id, ProductMediaRoleItem.tenant_id == user.tenant_id)
    )
    row = result.scalar_one_or_none()
    if row is None:
        raise HTTPException(status_code=404, detail="Media role item not found")
    await db.delete(row)
    await db.commit()
