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_attachments.models import ProductAttachment, ProductAttachmentType
from app.plugins.product_attachments.schemas import (
    AttachmentTypeIn,
    AttachmentTypeOut,
    ProductAttachmentIn,
    ProductAttachmentOut,
)


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


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


def _attachment_out(row: ProductAttachment) -> ProductAttachmentOut:
    type_obj = row.type
    return ProductAttachmentOut(
        id=row.id,
        tenant_id=row.tenant_id,
        product_id=row.product_id,
        type_id=row.type_id,
        title=row.title,
        file_url=row.file_url,
        mime_type=row.mime_type,
        file_size=row.file_size,
        sort_order=row.sort_order,
        is_active=bool(row.is_active),
        type_code=type_obj.code if type_obj else None,
        type_label=type_obj.label if type_obj 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-attachment-types", response_model=list[AttachmentTypeOut])
async def list_attachment_types(
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(ProductAttachmentType)
        .where(ProductAttachmentType.tenant_id == user.tenant_id)
        .order_by(ProductAttachmentType.sort_order, ProductAttachmentType.id)
    )
    return result.scalars().all()


@router.post("/product-attachment-types", response_model=AttachmentTypeOut, status_code=status.HTTP_201_CREATED)
async def create_attachment_type(
    body: AttachmentTypeIn,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_admin_user),
):
    row = ProductAttachmentType(
        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-attachment-types/{type_id}", response_model=AttachmentTypeOut)
async def update_attachment_type(
    type_id: int,
    body: AttachmentTypeIn,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(ProductAttachmentType).where(
            ProductAttachmentType.id == type_id,
            ProductAttachmentType.tenant_id == user.tenant_id,
        )
    )
    row = result.scalar_one_or_none()
    if row is None:
        raise HTTPException(status_code=404, detail="Attachment type 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-attachment-types/{type_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_attachment_type(
    type_id: int,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(ProductAttachmentType).where(
            ProductAttachmentType.id == type_id,
            ProductAttachmentType.tenant_id == user.tenant_id,
        )
    )
    row = result.scalar_one_or_none()
    if row is None:
        raise HTTPException(status_code=404, detail="Attachment type not found")
    await db.delete(row)
    await db.commit()


@router.get("/products/{product_id}/attachments", response_model=list[ProductAttachmentOut])
async def list_product_attachments(
    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(ProductAttachment)
        .options(selectinload(ProductAttachment.type))
        .join(ProductAttachmentType, ProductAttachment.type_id == ProductAttachmentType.id)
        .where(
            ProductAttachment.tenant_id == user.tenant_id,
            ProductAttachment.product_id == product_id,
        )
        .order_by(ProductAttachment.sort_order, ProductAttachment.id)
    )
    return [_attachment_out(row) for row in result.scalars().all()]


@router.post("/products/{product_id}/attachments", response_model=ProductAttachmentOut, status_code=status.HTTP_201_CREATED)
async def create_product_attachment(
    product_id: int,
    body: ProductAttachmentIn,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_admin_user),
):
    await _ensure_product(db, user.tenant_id, product_id)
    type_result = await db.execute(
        select(ProductAttachmentType).where(
            ProductAttachmentType.id == body.type_id,
            ProductAttachmentType.tenant_id == user.tenant_id,
        )
    )
    type_obj = type_result.scalar_one_or_none()
    if type_obj is None:
        raise HTTPException(status_code=404, detail="Attachment type not found")
    row = ProductAttachment(
        tenant_id=user.tenant_id,
        product_id=product_id,
        type_id=body.type_id,
        title=body.title,
        file_url=body.file_url,
        mime_type=body.mime_type,
        file_size=body.file_size,
        sort_order=body.sort_order,
        is_active=1 if body.is_active else 0,
    )
    row.type = type_obj
    db.add(row)
    await db.commit()
    await db.refresh(row)
    row.type = type_obj
    return _attachment_out(row)


@router.put("/product-attachments/{attachment_id}", response_model=ProductAttachmentOut)
async def update_product_attachment(
    attachment_id: int,
    body: ProductAttachmentIn,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(ProductAttachment)
        .where(ProductAttachment.id == attachment_id, ProductAttachment.tenant_id == user.tenant_id)
    )
    row = result.scalar_one_or_none()
    if row is None:
        raise HTTPException(status_code=404, detail="Attachment not found")
    type_result = await db.execute(
        select(ProductAttachmentType).where(
            ProductAttachmentType.id == body.type_id,
            ProductAttachmentType.tenant_id == user.tenant_id,
        )
    )
    type_obj = type_result.scalar_one_or_none()
    if type_obj is None:
        raise HTTPException(status_code=404, detail="Attachment type not found")
    row.type_id = body.type_id
    row.title = body.title
    row.file_url = body.file_url
    row.mime_type = body.mime_type
    row.file_size = body.file_size
    row.sort_order = body.sort_order
    row.is_active = 1 if body.is_active else 0
    row.type = type_obj
    await db.commit()
    await db.refresh(row)
    row.type = type_obj
    return _attachment_out(row)


@router.delete("/product-attachments/{attachment_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_product_attachment(
    attachment_id: int,
    db: AsyncSession = Depends(get_db),
    user: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(ProductAttachment).where(
            ProductAttachment.id == attachment_id,
            ProductAttachment.tenant_id == user.tenant_id,
        )
    )
    row = result.scalar_one_or_none()
    if row is None:
        raise HTTPException(status_code=404, detail="Attachment not found")
    await db.delete(row)
    await db.commit()
