# app/modules/marketplace/routes/api/store_letzshop.py
"""
Store API endpoints for Letzshop marketplace integration.

Provides store-level management of:
- Letzshop credentials
- Connection testing
- Order import and sync
- Fulfillment operations (confirm, reject, tracking)

Store Context: Uses token_store_id from JWT token.

All routes require module access control for the 'marketplace' module.
"""

import logging

from fastapi import APIRouter, Depends, Path, Query
from sqlalchemy.orm import Session

from app.api.deps import get_current_store_api, require_module_access
from app.core.database import get_db
from app.exceptions import ResourceNotFoundException, ValidationException
from app.modules.enums import FrontendType
from app.modules.marketplace.schemas import (
    FulfillmentConfirmRequest,
    FulfillmentOperationResponse,
    FulfillmentQueueItemResponse,
    FulfillmentQueueListResponse,
    FulfillmentRejectRequest,
    FulfillmentTrackingRequest,
    LetzshopConnectionTestRequest,
    LetzshopConnectionTestResponse,
    LetzshopCredentialsCreate,
    LetzshopCredentialsResponse,
    LetzshopCredentialsStatus,
    LetzshopCredentialsUpdate,
    LetzshopOrderDetailResponse,
    LetzshopOrderListResponse,
    LetzshopOrderResponse,
    LetzshopSuccessResponse,
    LetzshopSyncLogListResponse,
    LetzshopSyncLogResponse,
    LetzshopSyncTriggerRequest,
    LetzshopSyncTriggerResponse,
)
from app.modules.marketplace.services.letzshop import (
    CredentialsNotFoundError,
    LetzshopClientError,
    LetzshopCredentialsService,
    LetzshopOrderService,
    OrderNotFoundError,
)
from app.modules.orders.exceptions import OrderHasUnresolvedExceptionsException
from app.modules.orders.services.order_item_exception_service import (
    order_item_exception_service,
)
from app.modules.tenancy.schemas.auth import UserContext

store_letzshop_router = APIRouter(
    prefix="/letzshop",
    dependencies=[Depends(require_module_access("marketplace", FrontendType.STORE))],
)
logger = logging.getLogger(__name__)


# ============================================================================
# Helper Functions
# ============================================================================


def get_order_service(db: Session) -> LetzshopOrderService:
    """Get order service instance."""
    return LetzshopOrderService(db)


def get_credentials_service(db: Session) -> LetzshopCredentialsService:
    """Get credentials service instance."""
    return LetzshopCredentialsService(db)


# ============================================================================
# Status & Configuration
# ============================================================================


@store_letzshop_router.get("/status", response_model=LetzshopCredentialsStatus)
def get_letzshop_status(
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """Get Letzshop integration status for the current store."""
    creds_service = get_credentials_service(db)
    status = creds_service.get_status(current_user.token_store_id)
    return LetzshopCredentialsStatus(**status)


@store_letzshop_router.get("/credentials", response_model=LetzshopCredentialsResponse)
def get_credentials(
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """Get Letzshop credentials for the current store (API key is masked)."""
    creds_service = get_credentials_service(db)
    store_id = current_user.token_store_id

    try:
        credentials = creds_service.get_credentials_or_raise(store_id)
    except CredentialsNotFoundError:
        raise ResourceNotFoundException("LetzshopCredentials", str(store_id))

    return LetzshopCredentialsResponse(
        id=credentials.id,
        store_id=credentials.store_id,
        api_key_masked=creds_service.get_masked_api_key(store_id),
        api_endpoint=credentials.api_endpoint,
        auto_sync_enabled=credentials.auto_sync_enabled,
        sync_interval_minutes=credentials.sync_interval_minutes,
        last_sync_at=credentials.last_sync_at,
        last_sync_status=credentials.last_sync_status,
        last_sync_error=credentials.last_sync_error,
        created_at=credentials.created_at,
        updated_at=credentials.updated_at,
    )


@store_letzshop_router.post("/credentials", response_model=LetzshopCredentialsResponse)
def save_credentials(
    credentials_data: LetzshopCredentialsCreate,
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """Create or update Letzshop credentials for the current store."""
    creds_service = get_credentials_service(db)
    store_id = current_user.token_store_id

    credentials = creds_service.upsert_credentials(
        store_id=store_id,
        api_key=credentials_data.api_key,
        api_endpoint=credentials_data.api_endpoint,
        auto_sync_enabled=credentials_data.auto_sync_enabled,
        sync_interval_minutes=credentials_data.sync_interval_minutes,
    )
    db.commit()

    logger.info(f"Store user {current_user.email} updated Letzshop credentials")

    return LetzshopCredentialsResponse(
        id=credentials.id,
        store_id=credentials.store_id,
        api_key_masked=creds_service.get_masked_api_key(store_id),
        api_endpoint=credentials.api_endpoint,
        auto_sync_enabled=credentials.auto_sync_enabled,
        sync_interval_minutes=credentials.sync_interval_minutes,
        last_sync_at=credentials.last_sync_at,
        last_sync_status=credentials.last_sync_status,
        last_sync_error=credentials.last_sync_error,
        created_at=credentials.created_at,
        updated_at=credentials.updated_at,
    )


@store_letzshop_router.patch("/credentials", response_model=LetzshopCredentialsResponse)
def update_credentials(
    credentials_data: LetzshopCredentialsUpdate,
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """Partially update Letzshop credentials for the current store."""
    creds_service = get_credentials_service(db)
    store_id = current_user.token_store_id

    try:
        credentials = creds_service.update_credentials(
            store_id=store_id,
            api_key=credentials_data.api_key,
            api_endpoint=credentials_data.api_endpoint,
            auto_sync_enabled=credentials_data.auto_sync_enabled,
            sync_interval_minutes=credentials_data.sync_interval_minutes,
        )
        db.commit()
    except CredentialsNotFoundError:
        raise ResourceNotFoundException("LetzshopCredentials", str(store_id))

    return LetzshopCredentialsResponse(
        id=credentials.id,
        store_id=credentials.store_id,
        api_key_masked=creds_service.get_masked_api_key(store_id),
        api_endpoint=credentials.api_endpoint,
        auto_sync_enabled=credentials.auto_sync_enabled,
        sync_interval_minutes=credentials.sync_interval_minutes,
        last_sync_at=credentials.last_sync_at,
        last_sync_status=credentials.last_sync_status,
        last_sync_error=credentials.last_sync_error,
        created_at=credentials.created_at,
        updated_at=credentials.updated_at,
    )


@store_letzshop_router.delete("/credentials", response_model=LetzshopSuccessResponse)
def delete_credentials(
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """Delete Letzshop credentials for the current store."""
    creds_service = get_credentials_service(db)

    deleted = creds_service.delete_credentials(current_user.token_store_id)
    if not deleted:
        raise ResourceNotFoundException(
            "LetzshopCredentials", str(current_user.token_store_id)
        )
    db.commit()

    logger.info(f"Store user {current_user.email} deleted Letzshop credentials")
    return LetzshopSuccessResponse(success=True, message="Letzshop credentials deleted")


# ============================================================================
# Connection Testing
# ============================================================================


@store_letzshop_router.post("/test", response_model=LetzshopConnectionTestResponse)
def test_connection(
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """Test the Letzshop connection using stored credentials."""
    creds_service = get_credentials_service(db)

    success, response_time_ms, error = creds_service.test_connection(
        current_user.token_store_id
    )

    return LetzshopConnectionTestResponse(
        success=success,
        message="Connection successful" if success else "Connection failed",
        response_time_ms=response_time_ms,
        error_details=error,
    )


@store_letzshop_router.post("/test-key", response_model=LetzshopConnectionTestResponse)
def test_api_key(
    test_request: LetzshopConnectionTestRequest,
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """Test a Letzshop API key without saving it."""
    creds_service = get_credentials_service(db)

    success, response_time_ms, error = creds_service.test_api_key(
        api_key=test_request.api_key,
        api_endpoint=test_request.api_endpoint,
    )

    return LetzshopConnectionTestResponse(
        success=success,
        message="Connection successful" if success else "Connection failed",
        response_time_ms=response_time_ms,
        error_details=error,
    )


# ============================================================================
# Order Management
# ============================================================================


@store_letzshop_router.get("/orders", response_model=LetzshopOrderListResponse)
def list_orders(
    skip: int = Query(0, ge=0),
    limit: int = Query(50, ge=1, le=200),
    status: str | None = Query(None, description="Filter by order status"),
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """List Letzshop orders for the current store."""
    order_service = get_order_service(db)
    store_id = current_user.token_store_id

    orders, total = order_service.list_orders(
        store_id=store_id,
        skip=skip,
        limit=limit,
        status=status,
    )

    return LetzshopOrderListResponse(
        orders=[
            LetzshopOrderResponse(
                id=order.id,
                store_id=order.store_id,
                order_number=order.order_number,
                external_order_id=order.external_order_id,
                external_shipment_id=order.external_shipment_id,
                external_order_number=order.external_order_number,
                status=order.status,
                customer_email=order.customer_email,
                customer_name=f"{order.customer_first_name} {order.customer_last_name}",
                customer_locale=order.customer_locale,
                ship_country_iso=order.ship_country_iso,
                bill_country_iso=order.bill_country_iso,
                total_amount=order.total_amount,
                currency=order.currency,
                tracking_number=order.tracking_number,
                tracking_provider=order.tracking_provider,
                order_date=order.order_date,
                confirmed_at=order.confirmed_at,
                shipped_at=order.shipped_at,
                cancelled_at=order.cancelled_at,
                created_at=order.created_at,
                updated_at=order.updated_at,
            )
            for order in orders
        ],
        total=total,
        skip=skip,
        limit=limit,
    )


@store_letzshop_router.get("/orders/{order_id}", response_model=LetzshopOrderDetailResponse)
def get_order(
    order_id: int = Path(..., description="Order ID"),
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """Get a specific Letzshop order with full details."""
    order_service = get_order_service(db)

    try:
        order = order_service.get_order_or_raise(current_user.token_store_id, order_id)
    except OrderNotFoundError:
        raise ResourceNotFoundException("LetzshopOrder", str(order_id))

    return LetzshopOrderDetailResponse(
        # Base fields from LetzshopOrderResponse
        id=order.id,
        store_id=order.store_id,
        order_number=order.order_number,
        external_order_id=order.external_order_id,
        external_shipment_id=order.external_shipment_id,
        external_order_number=order.external_order_number,
        status=order.status,
        customer_email=order.customer_email,
        customer_name=f"{order.customer_first_name} {order.customer_last_name}",
        customer_locale=order.customer_locale,
        ship_country_iso=order.ship_country_iso,
        bill_country_iso=order.bill_country_iso,
        total_amount=order.total_amount,
        currency=order.currency,
        tracking_number=order.tracking_number,
        tracking_provider=order.tracking_provider,
        order_date=order.order_date,
        confirmed_at=order.confirmed_at,
        shipped_at=order.shipped_at,
        cancelled_at=order.cancelled_at,
        created_at=order.created_at,
        updated_at=order.updated_at,
        # Detail fields from LetzshopOrderDetailResponse
        customer_first_name=order.customer_first_name,
        customer_last_name=order.customer_last_name,
        customer_phone=order.customer_phone,
        ship_first_name=order.ship_first_name,
        ship_last_name=order.ship_last_name,
        ship_company=order.ship_company,
        ship_address_line_1=order.ship_address_line_1,
        ship_address_line_2=order.ship_address_line_2,
        ship_city=order.ship_city,
        ship_postal_code=order.ship_postal_code,
        bill_first_name=order.bill_first_name,
        bill_last_name=order.bill_last_name,
        bill_company=order.bill_company,
        bill_address_line_1=order.bill_address_line_1,
        bill_address_line_2=order.bill_address_line_2,
        bill_city=order.bill_city,
        bill_postal_code=order.bill_postal_code,
        external_data=order.external_data,
        customer_notes=order.customer_notes,
        internal_notes=order.internal_notes,
    )


@store_letzshop_router.post("/orders/import", response_model=LetzshopSyncTriggerResponse)
def import_orders(
    sync_request: LetzshopSyncTriggerRequest = LetzshopSyncTriggerRequest(),
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """Import new orders from Letzshop."""
    store_id = current_user.token_store_id
    order_service = get_order_service(db)
    creds_service = get_credentials_service(db)

    # Verify credentials exist
    try:
        creds_service.get_credentials_or_raise(store_id)
    except CredentialsNotFoundError:
        raise ValidationException("Letzshop credentials not configured")

    # Import orders
    try:
        with creds_service.create_client(store_id) as client:
            shipments = client.get_unconfirmed_shipments()

            orders_imported = 0
            orders_updated = 0
            errors = []

            for shipment in shipments:
                try:
                    existing = order_service.get_order_by_shipment_id(
                        store_id, shipment["id"]
                    )

                    if existing:
                        order_service.update_order_from_shipment(existing, shipment)
                        orders_updated += 1
                    else:
                        order_service.create_order(store_id, shipment)
                        orders_imported += 1

                except Exception as e:
                    errors.append(
                        f"Error processing shipment {shipment.get('id')}: {e}"
                    )

            db.commit()
            creds_service.update_sync_status(
                store_id,
                "success" if not errors else "partial",
                "; ".join(errors) if errors else None,
            )

            return LetzshopSyncTriggerResponse(
                success=True,
                message=f"Import completed: {orders_imported} imported, {orders_updated} updated",
                orders_imported=orders_imported,
                orders_updated=orders_updated,
                errors=errors,
            )

    except LetzshopClientError as e:
        creds_service.update_sync_status(store_id, "failed", str(e))
        return LetzshopSyncTriggerResponse(
            success=False,
            message=f"Import failed: {e}",
            errors=[str(e)],
        )


# ============================================================================
# Fulfillment Operations
# ============================================================================


@store_letzshop_router.post("/orders/{order_id}/confirm", response_model=FulfillmentOperationResponse)
def confirm_order(
    order_id: int = Path(..., description="Order ID"),
    confirm_request: FulfillmentConfirmRequest | None = None,
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Confirm inventory units for a Letzshop order.

    Raises:
        OrderHasUnresolvedExceptionsException: If order has unresolved product exceptions
    """
    store_id = current_user.token_store_id
    order_service = get_order_service(db)
    creds_service = get_credentials_service(db)

    try:
        order = order_service.get_order_or_raise(store_id, order_id)
    except OrderNotFoundError:
        raise ResourceNotFoundException("LetzshopOrder", str(order_id))

    # Check for unresolved exceptions (blocks confirmation)
    unresolved_count = order_item_exception_service.get_unresolved_exception_count(
        db, order_id
    )
    if unresolved_count > 0:
        raise OrderHasUnresolvedExceptionsException(order_id, unresolved_count)

    # Get inventory unit IDs from request or order items
    if confirm_request and confirm_request.inventory_unit_ids:
        inventory_unit_ids = confirm_request.inventory_unit_ids
    else:
        # Get inventory unit IDs from order items' external_item_id
        inventory_unit_ids = [
            item.external_item_id for item in order.items if item.external_item_id
        ]
    if not inventory_unit_ids:
        raise ValidationException("No inventory units to confirm")

    try:
        with creds_service.create_client(store_id) as client:
            result = client.confirm_inventory_units(inventory_unit_ids)

            # Check for errors
            if result.get("errors"):
                error_messages = [
                    f"{e.get('id', 'unknown')}: {e.get('message', 'Unknown error')}"
                    for e in result["errors"]
                ]
                return FulfillmentOperationResponse(
                    success=False,
                    message="Some inventory units could not be confirmed",
                    errors=error_messages,
                )

            # Update order status
            order_service.mark_order_confirmed(order)
            db.commit()

            return FulfillmentOperationResponse(
                success=True,
                message=f"Confirmed {len(inventory_unit_ids)} inventory units",
                confirmed_units=[u.get("id") for u in result.get("inventoryUnits", [])],
            )

    except LetzshopClientError as e:
        return FulfillmentOperationResponse(success=False, message=str(e))


@store_letzshop_router.post("/orders/{order_id}/reject", response_model=FulfillmentOperationResponse)
def reject_order(
    order_id: int = Path(..., description="Order ID"),
    reject_request: FulfillmentRejectRequest | None = None,
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """Reject inventory units for a Letzshop order."""
    store_id = current_user.token_store_id
    order_service = get_order_service(db)
    creds_service = get_credentials_service(db)

    try:
        order = order_service.get_order_or_raise(store_id, order_id)
    except OrderNotFoundError:
        raise ResourceNotFoundException("LetzshopOrder", str(order_id))

    # Get inventory unit IDs from request or order items
    if reject_request and reject_request.inventory_unit_ids:
        inventory_unit_ids = reject_request.inventory_unit_ids
    else:
        # Get inventory unit IDs from order items' external_item_id
        inventory_unit_ids = [
            item.external_item_id for item in order.items if item.external_item_id
        ]
    if not inventory_unit_ids:
        raise ValidationException("No inventory units to reject")

    try:
        with creds_service.create_client(store_id) as client:
            result = client.reject_inventory_units(inventory_unit_ids)

            if result.get("errors"):
                error_messages = [
                    f"{e.get('id', 'unknown')}: {e.get('message', 'Unknown error')}"
                    for e in result["errors"]
                ]
                return FulfillmentOperationResponse(
                    success=False,
                    message="Some inventory units could not be rejected",
                    errors=error_messages,
                )

            order_service.mark_order_rejected(order)
            db.commit()

            return FulfillmentOperationResponse(
                success=True,
                message=f"Rejected {len(inventory_unit_ids)} inventory units",
            )

    except LetzshopClientError as e:
        return FulfillmentOperationResponse(success=False, message=str(e))


@store_letzshop_router.post("/orders/{order_id}/tracking", response_model=FulfillmentOperationResponse)
def set_order_tracking(
    order_id: int = Path(..., description="Order ID"),
    tracking_request: FulfillmentTrackingRequest = ...,
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """Set tracking information for a Letzshop order."""
    store_id = current_user.token_store_id
    order_service = get_order_service(db)
    creds_service = get_credentials_service(db)

    try:
        order = order_service.get_order_or_raise(store_id, order_id)
    except OrderNotFoundError:
        raise ResourceNotFoundException("LetzshopOrder", str(order_id))

    if not order.external_shipment_id:
        raise ValidationException("Order does not have a shipment ID")

    try:
        with creds_service.create_client(store_id) as client:
            result = client.set_shipment_tracking(
                shipment_id=order.external_shipment_id,
                tracking_code=tracking_request.tracking_number,
                tracking_provider=tracking_request.tracking_carrier,
            )

            if result.get("errors"):
                error_messages = [
                    f"{e.get('code', 'unknown')}: {e.get('message', 'Unknown error')}"
                    for e in result["errors"]
                ]
                return FulfillmentOperationResponse(
                    success=False,
                    message="Failed to set tracking",
                    errors=error_messages,
                )

            order_service.set_order_tracking(
                order,
                tracking_request.tracking_number,
                tracking_request.tracking_carrier,
            )
            db.commit()

            return FulfillmentOperationResponse(
                success=True,
                message="Tracking information set",
                tracking_number=tracking_request.tracking_number,
                tracking_carrier=tracking_request.tracking_carrier,
            )

    except LetzshopClientError as e:
        return FulfillmentOperationResponse(success=False, message=str(e))


# ============================================================================
# Sync Logs
# ============================================================================


@store_letzshop_router.get("/logs", response_model=LetzshopSyncLogListResponse)
def list_sync_logs(
    skip: int = Query(0, ge=0),
    limit: int = Query(50, ge=1, le=200),
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """List Letzshop sync logs for the current store."""
    order_service = get_order_service(db)
    store_id = current_user.token_store_id

    logs, total = order_service.list_sync_logs(
        store_id=store_id,
        skip=skip,
        limit=limit,
    )

    return LetzshopSyncLogListResponse(
        logs=[
            LetzshopSyncLogResponse(
                id=log.id,
                store_id=log.store_id,
                operation_type=log.operation_type,
                direction=log.direction,
                status=log.status,
                records_processed=log.records_processed,
                records_succeeded=log.records_succeeded,
                records_failed=log.records_failed,
                error_details=log.error_details,
                started_at=log.started_at,
                completed_at=log.completed_at,
                duration_seconds=log.duration_seconds,
                triggered_by=log.triggered_by,
                created_at=log.created_at,
            )
            for log in logs
        ],
        total=total,
        skip=skip,
        limit=limit,
    )


# ============================================================================
# Fulfillment Queue
# ============================================================================


@store_letzshop_router.get("/queue", response_model=FulfillmentQueueListResponse)
def list_fulfillment_queue(
    skip: int = Query(0, ge=0),
    limit: int = Query(50, ge=1, le=200),
    status: str | None = Query(None, description="Filter by status"),
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """List fulfillment queue items for the current store."""
    order_service = get_order_service(db)
    store_id = current_user.token_store_id

    items, total = order_service.list_fulfillment_queue(
        store_id=store_id,
        skip=skip,
        limit=limit,
        status=status,
    )

    return FulfillmentQueueListResponse(
        items=[
            FulfillmentQueueItemResponse(
                id=item.id,
                store_id=item.store_id,
                letzshop_order_id=item.letzshop_order_id,
                operation=item.operation,
                payload=item.payload,
                status=item.status,
                attempts=item.attempts,
                max_attempts=item.max_attempts,
                last_attempt_at=item.last_attempt_at,
                next_retry_at=item.next_retry_at,
                error_message=item.error_message,
                completed_at=item.completed_at,
                response_data=item.response_data,
                created_at=item.created_at,
                updated_at=item.updated_at,
            )
            for item in items
        ],
        total=total,
        skip=skip,
        limit=limit,
    )


# ============================================================================
# Product Export
# ============================================================================


@store_letzshop_router.get("/export")
def export_products_letzshop(
    language: str = Query(
        "en", description="Language for title/description (en, fr, de)"
    ),
    include_inactive: bool = Query(False, description="Include inactive products"),
    current_user: UserContext = Depends(get_current_store_api),
    db: Session = Depends(get_db),
):
    """
    Export store products in Letzshop CSV format.

    Generates a Google Shopping compatible CSV file for Letzshop marketplace.
    The file uses tab-separated values and includes all required Letzshop fields.

    **Supported languages:** en, fr, de

    **CSV Format:**
    - Delimiter: Tab (\\t)
    - Encoding: UTF-8
    - Fields: id, title, description, price, availability, image_link, etc.

    Returns:
        CSV file as attachment (store_code_letzshop_export.csv)
    """
    from fastapi.responses import Response

    from app.modules.marketplace.services.letzshop_export_service import (
        letzshop_export_service,
    )
    from app.modules.tenancy.services.store_service import store_service

    store_id = current_user.token_store_id
    store = store_service.get_store_by_id(db, store_id)

    csv_content = letzshop_export_service.export_store_products(
        db=db,
        store_id=store_id,
        language=language,
        include_inactive=include_inactive,
    )

    filename = f"{store.store_code.lower()}_letzshop_export.csv"

    return Response(
        content=csv_content,
        media_type="text/csv; charset=utf-8",
        headers={
            "Content-Disposition": f'attachment; filename="{filename}"',
        },
    )
