from fastapi import APIRouter, Depends, HTTPException
from typing import List, Optional
import db
import schemas
import auth_utils
import json
import config
from dependencies import require_admin
from services.audit_service import audit_service

router = APIRouter(tags=["catalog"])

@router.get("/materials", response_model=List[schemas.MaterialBase])
async def get_materials():
    # Get active materials with their effective hourly price
    query = """
        SELECT m.*, 
               COALESCE(NULLIF(m.price_per_hour, 0), s.price_per_hour, %s) as effective_price_per_hour
        FROM materials m
        LEFT JOIN services s ON m.service_id = s.id
        WHERE m.is_active = TRUE
    """
    materials = db.execute_query(query, (config.DEFAULT_PRINTER_HOUR_PRICE,))
    
    # Get active stock
    stock = db.execute_query("SELECT material_id, color_name FROM warehouse_stock WHERE is_active = TRUE")
    
    # Map colors to materials
    color_map = {}
    for s in stock:
        m_id = s['material_id']
        if m_id not in color_map:
            color_map[m_id] = []
        color_map[m_id].append(s['color_name'])
        
    # Filter and attach colors
    result = []
    for m in materials:
        m['available_colors'] = color_map.get(m['id'], [])
        # Ensure numeric types for frontend
        m['price_per_cm3'] = float(m['price_per_cm3']) if m['price_per_cm3'] else 0.0
        m['effective_price_per_hour'] = float(m['effective_price_per_hour'])
        m['speed_coeff'] = float(m['speed_coeff']) if m['speed_coeff'] else 1.0
        
        # Only show on site if there are available colors in warehouse
        if m['available_colors']:
            result.append(m)
            
    return result

@router.get("/services", response_model=List[schemas.ServiceBase])
async def get_services():
    return db.execute_query("SELECT * FROM services WHERE is_active = TRUE")

@router.get("/admin/materials", response_model=List[schemas.MaterialBase])
async def admin_get_materials(admin: dict = Depends(require_admin)):
    # Get all materials
    materials = db.execute_query("SELECT * FROM materials ORDER BY id DESC")
    
    # Get stock (including inactive for admin)
    stock = db.execute_query("SELECT material_id, color_name FROM warehouse_stock")
    
    color_map = {}
    for s in stock:
        m_id = s['material_id']
        if m_id not in color_map:
            color_map[m_id] = []
        color_map[m_id].append(s['color_name'])
        
    for m in materials:
        # Merge warehouse colors with any legacy colors in available_colors
        legacy_colors = []
        if m.get('available_colors') and isinstance(m['available_colors'], str):
            try: legacy_colors = json.loads(m['available_colors'])
            except: pass
        
        # Priority to warehouse colors
        warehouse_colors = color_map.get(m['id'], [])
        # Combine them (unique)
        m['available_colors'] = list(set(warehouse_colors + (legacy_colors or [])))
        
    return materials

@router.post("/admin/materials")
async def admin_create_material(data: schemas.MaterialCreate, admin: dict = Depends(require_admin)):
    colors_json = json.dumps(data.available_colors) if data.available_colors else None
    query = "INSERT INTO materials (name_en, name_ru, name_ua, name_me, desc_en, desc_ru, desc_ua, desc_me, long_desc_en, long_desc_ru, long_desc_ua, long_desc_me, service_id, price_per_cm3, price_per_hour, speed_coeff, available_colors, is_active) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
    params = (data.name_en, data.name_ru, data.name_ua, data.name_me, data.desc_en, data.desc_ru, data.desc_ua, data.desc_me, data.long_desc_en, data.long_desc_ru, data.long_desc_ua, data.long_desc_me, data.service_id, data.price_per_cm3, data.price_per_hour, data.speed_coeff, colors_json, data.is_active)
    mat_id = db.execute_commit(query, params)
    
    await audit_service.log(
        user_id=admin.get("id"),
        action="create_material",
        target_type="material",
        target_id=mat_id,
        details=data.dict()
    )
    return {"id": mat_id}

@router.patch("/admin/materials/{mat_id}")
async def admin_update_material(mat_id: int, data: schemas.MaterialUpdate, admin: dict = Depends(require_admin)):
    update_fields = []
    params = []
    for field, value in data.dict(exclude_unset=True).items():
        update_fields.append(f"{field} = %s")
        if isinstance(value, list):
            params.append(json.dumps(value))
        else:
            params.append(value)
    if update_fields:
        query = f"UPDATE materials SET {', '.join(update_fields)} WHERE id = %s"
        params.append(mat_id)
        db.execute_commit(query, tuple(params))
        
        await audit_service.log(
            user_id=admin.get("id"),
            action="update_material",
            target_type="material",
            target_id=mat_id,
            details={"updated_fields": data.dict(exclude_unset=True)}
        )
    return {"id": mat_id}

@router.get("/admin/services", response_model=List[schemas.ServiceBase])
async def admin_get_services(admin: dict = Depends(require_admin)):
    return db.execute_query("SELECT * FROM services ORDER BY id DESC")

@router.post("/admin/services")
async def admin_create_service(data: schemas.ServiceCreate, admin: dict = Depends(require_admin)):
    query = "INSERT INTO services (name_en, name_ru, name_ua, name_me, desc_en, desc_ru, desc_ua, desc_me, tech_type, price_per_hour, is_active) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"
    srv_id = db.execute_commit(query, (data.name_en, data.name_ru, data.name_ua, data.name_me, data.desc_en, data.desc_ru, data.desc_ua, data.desc_me, data.tech_type, data.price_per_hour, data.is_active))
    
    await audit_service.log(
        user_id=admin.get("id"),
        action="create_service",
        target_type="service",
        target_id=srv_id,
        details=data.dict()
    )
    return {"id": srv_id}

@router.patch("/admin/services/{srv_id}")
async def admin_update_service(srv_id: int, data: schemas.ServiceUpdate, admin: dict = Depends(require_admin)):
    update_fields = []
    params = []
    for field, value in data.dict(exclude_unset=True).items():
        update_fields.append(f"{field} = %s")
        if isinstance(value, list):
            params.append(json.dumps(value))
        else:
            params.append(value)
    if update_fields:
        query = f"UPDATE services SET {', '.join(update_fields)} WHERE id = %s"
        params.append(srv_id)
        db.execute_commit(query, tuple(params))
        
        await audit_service.log(
            user_id=admin.get("id"),
            action="update_service",
            target_type="service",
            target_id=srv_id,
            details={"updated_fields": data.dict(exclude_unset=True)}
        )
    return {"id": srv_id}

@router.delete("/admin/materials/{mat_id}")
async def admin_delete_material(mat_id: int, admin: dict = Depends(require_admin)):
    db.execute_commit("DELETE FROM materials WHERE id = %s", (mat_id,))
    await audit_service.log(
        user_id=admin.get("id"),
        action="delete_material",
        target_type="material",
        target_id=mat_id
    )
    return {"id": mat_id, "status": "deleted"}

@router.delete("/admin/services/{srv_id}")
async def admin_delete_service(srv_id: int, admin: dict = Depends(require_admin)):
    db.execute_commit("DELETE FROM services WHERE id = %s", (srv_id,))
    await audit_service.log(
        user_id=admin.get("id"),
        action="delete_service",
        target_type="service",
        target_id=srv_id
    )
    return {"id": srv_id, "status": "deleted"}
