"""Record a wine the user has encountered (not added to cellar)."""

import asyncio
import json
import logging
from typing import Annotated

from fastapi import File, Form, HTTPException, UploadFile, status

from winebox.models import InventoryInfo, Wine
from winebox.models.wine import WineCollection
from winebox.schemas.wine import WineWithInventory
from winebox.services.analytics import posthog_service
from winebox.services.auth import RequireAuth
from winebox.services.xwines_enrichment import enrich_parsed_with_xwines

from ._common import (
    MAX_FIELD_LENGTH,
    MAX_NAME_LENGTH,
    MAX_NOTES_LENGTH,
    MAX_OCR_TEXT_LENGTH,
    get_media_type,
    image_storage,
    ocr_service,
    vision_service,
    wine_parser,
)

logger = logging.getLogger(__name__)


async def record_met_wine(
    current_user: RequireAuth,
    front_label: Annotated[UploadFile, File(description="Front label image")],
    back_label: Annotated[UploadFile | None, File(description="Back label image")] = None,
    name: Annotated[str | None, Form(max_length=MAX_NAME_LENGTH, description="Wine name")] = None,
    winery: Annotated[str | None, Form(max_length=MAX_FIELD_LENGTH)] = None,
    vintage: Annotated[int | None, Form(ge=1900, le=2100)] = None,
    grape_variety: Annotated[str | None, Form(max_length=MAX_FIELD_LENGTH)] = None,
    region: Annotated[str | None, Form(max_length=MAX_FIELD_LENGTH)] = None,
    sub_region: Annotated[str | None, Form(max_length=MAX_FIELD_LENGTH)] = None,
    appellation: Annotated[str | None, Form(max_length=MAX_FIELD_LENGTH)] = None,
    country: Annotated[str | None, Form(max_length=MAX_FIELD_LENGTH)] = None,
    classification: Annotated[str | None, Form(max_length=MAX_FIELD_LENGTH)] = None,
    alcohol_percentage: Annotated[float | None, Form(ge=0, le=100)] = None,
    wine_type_id: Annotated[str | None, Form(max_length=MAX_FIELD_LENGTH)] = None,
    notes: Annotated[str | None, Form(max_length=MAX_NOTES_LENGTH)] = None,
    front_label_text: Annotated[str | None, Form(max_length=MAX_OCR_TEXT_LENGTH)] = None,
    back_label_text: Annotated[str | None, Form(max_length=MAX_OCR_TEXT_LENGTH)] = None,
    custom_fields: Annotated[str | None, Form(max_length=5000)] = None,
) -> WineWithInventory:
    """Record a wine the user has encountered without adding it to the cellar.

    Same scan + enrichment pipeline as check-in, but creates a met wine
    with quantity=0 and no transaction.
    """
    # Save images
    front_image_path = await image_storage.save_image(front_label)
    back_image_path = None
    if back_label and back_label.filename:
        back_image_path = await image_storage.save_image(back_label)

    # Use pre-scanned text if provided
    front_text = front_label_text or ""
    back_text = back_label_text

    # Only scan if no pre-scanned text was provided and no name given
    if not front_label_text and not name:
        logger.info("No pre-scanned text provided, scanning labels...")

        async def read_front() -> bytes:
            await front_label.seek(0)
            return await front_label.read()

        async def read_back() -> bytes | None:
            if back_label and back_label.filename:
                await back_label.seek(0)
                return await back_label.read()
            return None

        front_data, back_data = await asyncio.gather(read_front(), read_back())

        parsed_data = {}
        if vision_service.is_available():
            logger.info("Using Claude Vision for met wine analysis")
            try:
                front_media_type = get_media_type(front_label.filename)
                back_media_type = get_media_type(back_label.filename if back_label else None)
                result = await vision_service.analyze_labels(
                    front_image_data=front_data,
                    back_image_data=back_data,
                    front_media_type=front_media_type,
                    back_media_type=back_media_type,
                )
                parsed_data = result
                front_text = result.get("raw_text", "")
                back_text = result.get("back_label_text")
            except Exception as e:
                logger.warning(f"Claude Vision failed, falling back to Tesseract: {e}")

        if not parsed_data.get("name"):
            logger.info("Using Tesseract OCR for met wine analysis")
            front_text = await ocr_service.extract_text(front_image_path)
            if back_image_path:
                back_text = await ocr_service.extract_text(back_image_path)
            combined_text = front_text
            if back_text:
                combined_text = f"{front_text}\n{back_text}"
            parsed_data = wine_parser.parse(combined_text)

        name = name or parsed_data.get("name")
        winery = winery or parsed_data.get("winery")
        vintage = vintage or parsed_data.get("vintage")
        grape_variety = grape_variety or parsed_data.get("grape_variety")
        region = region or parsed_data.get("region")
        sub_region = sub_region or parsed_data.get("sub_region")
        appellation = appellation or parsed_data.get("appellation")
        country = country or parsed_data.get("country")
        classification = classification or parsed_data.get("classification")
        alcohol_percentage = alcohol_percentage or parsed_data.get("alcohol_percentage")

    # Enrich with X-Wines reference data
    enrichment_input = {
        "name": name,
        "winery": winery,
        "grape_variety": grape_variety,
        "region": region,
        "country": country,
        "alcohol_percentage": alcohol_percentage,
    }
    enrichment_input = await enrich_parsed_with_xwines(enrichment_input)
    enriched_fields = enrichment_input.pop("enriched_fields", None)
    xwines_id = enrichment_input.pop("xwines_id", None)
    winery = enrichment_input.get("winery") or winery
    grape_variety = enrichment_input.get("grape_variety") or grape_variety
    region = enrichment_input.get("region") or region
    country = enrichment_input.get("country") or country
    alcohol_percentage = enrichment_input.get("alcohol_percentage") or alcohol_percentage

    wine_name = name or "Unknown Wine"

    # Parse custom fields JSON
    parsed_custom_fields = None
    custom_fields_text = None
    if custom_fields:
        try:
            parsed_custom_fields = json.loads(custom_fields)
            if not isinstance(parsed_custom_fields, dict):
                raise ValueError("custom_fields must be a JSON object")
            parsed_custom_fields = {str(k): str(v) for k, v in parsed_custom_fields.items()}
            custom_fields_text = " ".join(
                f"{k} {v}" for k, v in parsed_custom_fields.items()
            ) if parsed_custom_fields else None
        except (json.JSONDecodeError, ValueError) as e:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=f"Invalid custom_fields JSON: {e}",
            )

    # Create wine document with collection="met" and quantity=0
    wine = Wine(
        owner_id=current_user.id,
        collection=WineCollection.MET,
        name=wine_name,
        winery=winery,
        vintage=vintage,
        grape_variety=grape_variety,
        region=region,
        sub_region=sub_region,
        appellation=appellation,
        country=country,
        classification=classification,
        alcohol_percentage=alcohol_percentage,
        wine_type_id=wine_type_id,
        front_label_text=front_text,
        back_label_text=back_text,
        front_label_image_path=front_image_path,
        back_label_image_path=back_image_path,
        enriched_fields=enriched_fields or None,
        xwines_id=xwines_id,
        custom_fields=parsed_custom_fields,
        custom_fields_text=custom_fields_text,
        inventory=InventoryInfo(quantity=0),
    )
    await wine.insert()

    # No transaction created for met wines

    posthog_service.capture(
        distinct_id=str(current_user.id),
        event="wine_met_recorded",
        properties={
            "scan_method": "claude_vision" if vision_service.is_available() else "tesseract",
            "country": country,
            "wine_id": str(wine.id),
        },
    )

    return WineWithInventory.model_validate(wine)
