import csv
import io
import os
import shutil
import time
import uuid
from datetime import date, datetime
from typing import List, Optional
from fastapi import APIRouter, Depends, Query, Request, UploadFile, File, Form, HTTPException
from fastapi.responses import StreamingResponse
from starlette.requests import ClientDisconnect
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.database import get_db
from app.core.security import require_permission, require_permission_any, get_current_user
from app.models.core_models import LoginUsers
from . import schemas, service
from . import production_dashboard
from . import production_report_service

router = APIRouter()
 
 
@router.get('/masters', response_model=schemas.YardMastersOut)
async def get_masters(
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission_any(['YARD', 'INVENTORY'], 'view')),
):
    return await service.get_masters(db)


@router.get('/chassis', response_model=list[schemas.ChassisListItem])
async def list_chassis(
    status: str | None = Query(None, description="YARD_PENDING_CHECK / YARD_CHECKED / HANDED_TO_PRODUCTION"),
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'view')),
):
    return await service.list_chassis(db, status)


@router.post('/chassis', response_model=schemas.ChassisOut, status_code=201)
async def create_chassis(
    payload: schemas.ChassisCreate,
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(require_permission('YARD', 'create')),
):
    return await service.create_chassis(db, payload, user.user_id)


@router.get('/chassis/{chassis_id}', response_model=schemas.ChassisDetailOut)
async def get_chassis_detail(
    chassis_id: uuid.UUID,
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission_any(['YARD', 'INVENTORY'], 'view')),
):
    return await service.get_chassis_detail(db, chassis_id)


@router.put('/chassis/{chassis_id}/arrival', response_model=schemas.ChassisOut)
async def update_arrival(
    chassis_id: uuid.UUID,
    payload: schemas.UpdateArrivalRequest,
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(require_permission('YARD', 'edit')),
):
    return await service.update_arrival(db, chassis_id, payload)


@router.put('/chassis/{chassis_id}/da-lite', response_model=schemas.ChassisOut)
async def update_da_lite(
    chassis_id: uuid.UUID,
    request: Request,
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(require_permission('YARD', 'edit')),
):
    content_type = request.headers.get("content-type", "")
    photo_url = None
    da_lite_status = None
    da_lite_remarks = None
    if "multipart/form-data" in content_type:
        try:
            form = await request.form()
        except ClientDisconnect:
            raise HTTPException(status_code=499, detail="Upload cancelled by client")
        
        da_lite_status = form.get("da_lite_status")
        da_lite_remarks = form.get("da_lite_remarks")
        file_obj = form.get("file")
        if file_obj and hasattr(file_obj, "filename") and file_obj.filename:
            ext = os.path.splitext(file_obj.filename)[1] or ".jpg"
            filename = f"dalite_{chassis_id}_{int(time.time())}{ext}"
            os.makedirs("uploads/da_lite", exist_ok=True)
            file_path = os.path.join("uploads/da_lite", filename)
            with open(file_path, "wb") as buffer:
                shutil.copyfileobj(file_obj.file, buffer)
            photo_url = f"/uploads/da_lite/{filename}"
    else:
        try:
            body = await request.json()
            da_lite_status = body.get("da_lite_status")
            da_lite_remarks = body.get("da_lite_remarks")
            photo_url = body.get("da_lite_photo_url")
        except Exception:
            pass

    return await service.update_da_lite(db, chassis_id, da_lite_status, da_lite_remarks, user.user_id, photo_url)


@router.delete('/chassis/{chassis_id}/da-lite/photo', response_model=schemas.ChassisOut)
async def delete_da_lite_photo(
    chassis_id: uuid.UUID,
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(require_permission('YARD', 'edit')),
):
    return await service.delete_da_lite_photo(db, chassis_id, user.user_id)


@router.put('/chassis/{chassis_id}/qa-checklist')
async def upsert_qa_checklist(
    chassis_id: uuid.UUID,
    payload: schemas.QaChecklistBulkUpdate,
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'edit')),
):
    await service.upsert_qa_checklist(db, chassis_id, payload.entries)
    return {"message": "Checklist saved"}


@router.post('/qa-items', response_model=schemas.QaItemOut, status_code=201)
async def create_qa_item(
    payload: schemas.QaItemCreate,
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'edit')),
):
    return await service.create_qa_item(db, payload)


@router.put('/qa-items/{item_id}', response_model=schemas.QaItemOut)
async def update_qa_item(
    item_id: uuid.UUID,
    payload: schemas.QaItemUpdate,
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'edit')),
):
    return await service.update_qa_item(db, item_id, payload)


@router.delete('/qa-items/{item_id}')
async def delete_qa_item(
    item_id: uuid.UUID,
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'edit')),
):
    return await service.delete_qa_item(db, item_id)


@router.post('/handover-parts', response_model=schemas.HandoverPartOut, status_code=201)
async def create_handover_part(
    payload: schemas.HandoverPartCreate,
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'edit')),
):
    return await service.create_handover_part(db, payload)


@router.post('/chassis/{chassis_id}/movement', response_model=schemas.MovementLogOut, status_code=201)
async def add_movement_log(
    chassis_id: uuid.UUID,
    payload: schemas.MovementLogCreate,
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'edit')),
):
    return await service.add_movement_log(db, chassis_id, payload)


@router.put('/chassis/{chassis_id}/store-handover', response_model=schemas.StoreHandoverOut)
async def upsert_store_handover(
    chassis_id: uuid.UUID,
    payload: schemas.StoreHandoverUpdate,
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'edit')),
):
    return await service.upsert_store_handover(db, chassis_id, payload)


@router.post('/chassis/{chassis_id}/store-handover/approve/{role}')
async def approve_store_handover(
    chassis_id: uuid.UUID,
    role: str,
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(require_permission_any(['YARD', 'INVENTORY'], 'view')),
):
    return await service.approve_store_handover(db, chassis_id, role, user.user_id)


@router.get('/pending-store-handovers')
async def pending_store_handovers(
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(require_permission_any(['YARD', 'INVENTORY'], 'view')),
):
    return await service.get_pending_store_handovers(db, user)

@router.get('/history-store-handovers')
async def history_store_handovers(
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(require_permission_any(['YARD', 'INVENTORY'], 'view')),
):
    return await service.get_history_store_handovers(db, user)


@router.post('/chassis/{chassis_id}/handover-to-production', response_model=schemas.ChassisOut)
async def handover_to_production(
    chassis_id: uuid.UUID,
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(require_permission('YARD', 'approve')),
):
    return await service.handover_to_production(db, chassis_id, user.user_id)


@router.get('/reports/daily')
async def daily_report(
    report_date: date = Query(..., alias="date"),
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'view')),
):
    return await service.daily_report(db, report_date)


import openpyxl
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.utils import get_column_letter


def generate_daily_excel_report(rows: list[dict], report_date: date) -> io.BytesIO:
    wb = openpyxl.Workbook()
    ws = wb.active or wb.create_sheet()
    ws.title = "Daily Receiving Report"
    ws.views.sheetView[0].showGridLines = True

    # Columns: (data_key, capitalized_header_title)
    columns_spec = [
        ('chassis_no', 'Chassis No'),
        ('model_name', 'Model Name'),
        ('yard_location', 'Yard'),
        ('fuel_type', 'Fuel Type'),
        ('light_type', 'Light Type'),
        ('fuel_receiving', 'Fuel Receiving'),
        ('dealer_name', 'Dealer Name'),
        ('remarks', 'Remarks'),
        ('transport_name', 'Transport Name'),
        ('da_lite_status', 'DA Lite Status'),
        ('voltage', 'Voltage'),
    ]

    header_titles = [col[1] for col in columns_spec]
    ws.append(header_titles)

    # 1. Header Row Styling
    header_font = Font(name='Segoe UI', size=11, bold=True, color='FFFFFF')
    header_fill = PatternFill(start_color='1F4E79', end_color='1F4E79', fill_type='solid')
    header_alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)
    thin_border = Border(
        left=Side(style='thin', color='D9D9D9'),
        right=Side(style='thin', color='D9D9D9'),
        top=Side(style='thin', color='D9D9D9'),
        bottom=Side(style='thin', color='D9D9D9'),
    )

    ws.row_dimensions[1].height = 28

    for cell in ws[1]:
        cell.font = header_font
        cell.fill = header_fill
        cell.alignment = header_alignment
        cell.border = thin_border

    # 2. Data Row Styling
    even_fill = PatternFill(start_color='FFFFFF', end_color='FFFFFF', fill_type='solid')
    odd_fill = PatternFill(start_color='F8FAFC', end_color='F8FAFC', fill_type='solid')
    data_font = Font(name='Segoe UI', size=10)
    center_cols = {'chassis_no', 'model_name', 'fuel_type', 'light_type', 'fuel_receiving', 'da_lite_status', 'voltage'}

    for row_idx, r in enumerate(rows, start=2):
        ws.row_dimensions[row_idx].height = 20
        row_fill = odd_fill if row_idx % 2 == 1 else even_fill
        for col_idx, (key, _) in enumerate(columns_spec, start=1):
            raw_val = r.get(key)
            if key == 'light_type' and raw_val:
                val = 'Square Light' if raw_val == 'SQUARE_LIGHT' else 'Round Light' if raw_val == 'ROUND_LIGHT' else str(raw_val).title()
            elif key == 'fuel_receiving' and raw_val is not None:
                val = f"{raw_val} L" if r.get('fuel_type') == 'DIESEL' else f"{raw_val} BAR" if r.get('fuel_type') == 'CNG' else str(raw_val)
            else:
                val = str(raw_val) if raw_val is not None else ''

            cell = ws.cell(row=row_idx, column=col_idx, value=val)
            cell.font = data_font
            cell.fill = row_fill
            cell.border = thin_border
            align_h = 'center' if key in center_cols else 'left'
            cell.alignment = Alignment(horizontal=align_h, vertical='center')

    # 3. Freeze Header Row
    ws.freeze_panes = 'A2'

    # 4. Filter on Headers
    last_row = max(len(rows) + 1, 1)
    last_col_letter = get_column_letter(len(columns_spec))
    ws.auto_filter.ref = f'A1:{last_col_letter}{last_row}'

    # 5. Column Widths
    for col in ws.columns:
        col_idx = col[0].column
        col_letter = get_column_letter(int(col_idx)) if col_idx is not None else 'A'
        max_len = max(len(str(cell.value or '')) for cell in col)
        ws.column_dimensions[col_letter].width = max(max_len + 4, 14)

    buf = io.BytesIO()
    wb.save(buf)
    buf.seek(0)
    return buf


def format_date_dd_mm_yy(d: date | str | None) -> str:
    if not d:
        return ""
    if isinstance(d, (date, datetime)):
        return d.strftime("%d_%m_%y")
    try:
        parts = d.split('T')[0].split('-')
        if len(parts) == 3:
            return f"{parts[2]}_{parts[1]}_{parts[0][-2:]}"
    except Exception:
        pass
    return d


def generate_period_excel_report(rows: list[dict], group_by: str, start: date, end: date) -> io.BytesIO:
    wb = openpyxl.Workbook()
    ws = wb.active or wb.create_sheet()
    ws.title = f"{group_by.capitalize()} Report"
    ws.views.sheetView[0].showGridLines = True

    columns_spec = [
        ('period', 'Period'),
        ('total_inwarded', 'Total Inwarded'),
        ('da_lite_ok', 'DA Lite OK'),
        ('da_lite_hold', 'DA Lite Hold'),
        ('handed_to_production', 'Handed to Production'),
        ('straight_pass_pct', 'Straight Pass %'),
        ('rework_count', 'Rework Count'),
    ]

    header_titles = [col[1] for col in columns_spec]
    ws.append(header_titles)

    header_font = Font(name='Segoe UI', size=11, bold=True, color='FFFFFF')
    header_fill = PatternFill(start_color='1F4E79', end_color='1F4E79', fill_type='solid')
    header_alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)
    thin_border = Border(
        left=Side(style='thin', color='D9D9D9'),
        right=Side(style='thin', color='D9D9D9'),
        top=Side(style='thin', color='D9D9D9'),
        bottom=Side(style='thin', color='D9D9D9'),
    )

    ws.row_dimensions[1].height = 28
    for cell in ws[1]:
        cell.font = header_font
        cell.fill = header_fill
        cell.alignment = header_alignment
        cell.border = thin_border

    even_fill = PatternFill(start_color='FFFFFF', end_color='FFFFFF', fill_type='solid')
    odd_fill = PatternFill(start_color='F8FAFC', end_color='F8FAFC', fill_type='solid')
    data_font = Font(name='Segoe UI', size=10)

    for row_idx, r in enumerate(rows, start=2):
        ws.row_dimensions[row_idx].height = 20
        row_fill = odd_fill if row_idx % 2 == 1 else even_fill
        for col_idx, (key, _) in enumerate(columns_spec, start=1):
            raw_val = r.get(key)
            if key == 'period' and raw_val:
                val = str(raw_val)[:10]
            elif key == 'straight_pass_pct' and raw_val is not None:
                val = f"{raw_val}%"
            else:
                val = str(raw_val) if raw_val is not None else ''

            cell = ws.cell(row=row_idx, column=col_idx, value=val)
            cell.font = data_font
            cell.fill = row_fill
            cell.border = thin_border
            cell.alignment = Alignment(horizontal='center', vertical='center')

    ws.freeze_panes = 'A2'
    last_row = max(len(rows) + 1, 1)
    ws.auto_filter.ref = f'A1:{get_column_letter(len(columns_spec))}{last_row}'

    for col in ws.columns:
        col_idx = col[0].column
        col_letter = get_column_letter(int(col_idx)) if col_idx is not None else 'A'
        max_len = max(len(str(cell.value or '')) for cell in col)
        ws.column_dimensions[col_letter].width = max(max_len + 4, 15)

    buf = io.BytesIO()
    wb.save(buf)
    buf.seek(0)
    return buf


@router.get('/reports/daily.xlsx')
async def daily_report_xlsx(
    report_date: date = Query(..., alias="date"),
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'view')),
):
    rows = await service.daily_report(db, report_date)
    buf = generate_daily_excel_report(rows, report_date)
    fn = f"Chassis_receiving_report_{format_date_dd_mm_yy(report_date)}.xlsx"
    return StreamingResponse(
        buf,
        media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        headers={'Content-Disposition': f'attachment; filename="{fn}"'},
    )


@router.get('/reports/daily.csv')
async def daily_report_csv(
    report_date: date = Query(..., alias="date"),
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'view')),
):
    rows = await service.daily_report(db, report_date)
    buf = generate_daily_excel_report(rows, report_date)
    fn = f"Chassis_receiving_report_{format_date_dd_mm_yy(report_date)}.xlsx"
    return StreamingResponse(
        buf,
        media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        headers={'Content-Disposition': f'attachment; filename="{fn}"'},
    )


@router.get('/reports/period')
async def period_summary(
    start: date = Query(...),
    end: date = Query(...),
    group_by: str = Query('day', pattern='^(day|week|month)$'),
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'view')),
):
    return await service.period_summary(db, start, end, group_by)


@router.get('/reports/period.xlsx')
async def period_summary_xlsx(
    start: date = Query(...),
    end: date = Query(...),
    group_by: str = Query('day', pattern='^(day|week|month)$'),
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'view')),
):
    rows = await service.period_summary(db, start, end, group_by)
    buf = generate_period_excel_report(rows, group_by, start, end)
    label = 'weekly' if group_by == 'week' else 'monthly' if group_by == 'month' else 'daily'
    fn = f"Chassis_{label}_report_{format_date_dd_mm_yy(start)}_to_{format_date_dd_mm_yy(end)}.xlsx"
    return StreamingResponse(
        buf,
        media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        headers={'Content-Disposition': f'attachment; filename="{fn}"'},
    )


@router.get('/reports/pod')
async def pod_report(
    start: date | None = Query(None),
    end: date | None = Query(None),
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'view')),
):
    return await service.pod_report(db, start, end)


@router.get('/reports/pod.csv')
async def pod_report_csv(
    start: date | None = Query(None),
    end: date | None = Query(None),
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'view')),
):
    data = await service.pod_report(db, start, end)
    buffer = io.StringIO()
    writer = csv.writer(buffer)

    # Section 1: Monthly Summary
    writer.writerow(['--- MONTHLY SUMMARY ---'])
    writer.writerow(['Month', 'Total Checked Cowl', 'Total Loss %', 'Total Straight Pass %', 'Stopped Cowl', 'Rework Status', 'Total Hold Pending'])
    for m in data.get('monthly_summary', []):
        writer.writerow([
            m['month_label'], m['total_checked_cowl'], f"{m['loss_pct']}%", f"{m['straight_pass_pct']}%",
            m['stopped_cowl'], m['rework_status'], m['total_hold_pending']
        ])

    writer.writerow([])
    # Section 2: Dealer Breakdown
    writer.writerow(['--- DEALER / LOCATION BREAKDOWN ---'])
    for d in data.get('dealer_breakdown', []):
        writer.writerow([f"DEALER: {d['dealer_name']}"])
        writer.writerow(['Date', 'Total Checked Cowl', 'Total Loss %', 'Total Straight Pass %', 'Stopped Cowl', 'Rework Status', 'Total Hold Pending'])
        for r in d.get('rows', []):
            writer.writerow([
                r['date'], r['total_checked_cowl'], f"{r['loss_pct']}%", f"{r['straight_pass_pct']}%",
                r['stopped_cowl'], r['rework_status'], r['total_hold_pending']
            ])
        summ = d.get('summary', {})
        writer.writerow([
            'TOTAL', summ.get('total_checked_cowl', 0), f"{summ.get('loss_pct', 0)}%", f"{summ.get('straight_pass_pct', 0)}%",
            summ.get('stopped_cowl', 0), summ.get('rework_status', 0), summ.get('total_hold_pending', 0)
        ])
        writer.writerow([])

    buffer.seek(0)
    fn = f"Chassis_pod_report_{format_date_dd_mm_yy(data.get('start_date'))}_to_{format_date_dd_mm_yy(data.get('end_date'))}.csv"
    return StreamingResponse(
        iter([buffer.getvalue()]),
        media_type='text/csv',
        headers={'Content-Disposition': f'attachment; filename="{fn}"'},
    )


# ── QR TRACKING ENDPOINTS ──────────────────────────────────────

@router.get('/track/{chassis_no}', response_model=schemas.ChassisTrackingOut)
async def get_tracking_info(
    chassis_no: str,
    db: AsyncSession = Depends(get_db),
):
    """Public tracking info for QR scan (no auth required)"""
    return await service.get_tracking_info(db, chassis_no)


@router.post('/track/{chassis_no}/scan', response_model=schemas.ChassisTrackingOut)
async def update_tracking_status(
    chassis_no: str,
    payload: schemas.TrackingScanInput,
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(require_permission('YARD', 'edit')),
):
    """Authenticated scan endpoint to update tracking status (CHASSIS_IN -> WIP -> DISPATCHED)"""
    return await service.update_tracking_status(db, chassis_no, payload, user.user_id)


# ── SUPERVISOR STATION SCAN CONSOLE ───────────────────────────

@router.post('/supervisor-scan', response_model=schemas.SupervisorScanResponse)
async def supervisor_scan(
    payload: schemas.SupervisorScanInput,
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(get_current_user),
):
    """Supervisor scans chassis at a station — auto-detects ARRIVAL (IN) or COMPLETION (OUT)."""
    return await service.supervisor_station_scan(db, payload, user.user_id)


@router.get('/supervisor/stations', response_model=List[schemas.SupervisorStationSummary])
async def get_supervisor_stations(
    db: AsyncSession = Depends(get_db),
    _: LoginUsers = Depends(get_current_user),
):
    """List all active stations in sequence order with live chassis counts (IN / OUT)."""
    return await service.get_supervisor_stations(db)


@router.get('/supervisor/station/{station_id}/chassis', response_model=List[schemas.SupervisorStationChassisItem])
async def get_supervisor_station_chassis(
    station_id: uuid.UUID,
    db: AsyncSession = Depends(get_db),
    _: LoginUsers = Depends(get_current_user),
):
    """List chassis currently at this station with elapsed dwell times and IN/OUT status."""
    return await service.get_supervisor_station_chassis(db, station_id)






# ── PRODUCTION DASHBOARD ──────────────────────────────────────

@router.get('/production-dashboard')
async def get_production_dashboard(
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('PRODUCTION', 'view')),
):
    """Aggregated production dashboard: KPIs, station pipeline, WIP list, activity feed"""
    return await production_dashboard.get_production_dashboard(db)


# ── DOCUMENTS ─────────────────────────────────────────

@router.post('/chassis/{chassis_id}/documents', response_model=schemas.DocumentOut, status_code=201)
async def upload_document(
    chassis_id: uuid.UUID,
    document_type: str = Form(...),
    document_number: str = Form(None),
    issue_date: str = Form(None),
    valid_until: str = Form(None),
    issuing_authority: str = Form(None),
    file: UploadFile = File(None),
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(require_permission('YARD', 'edit')),
):
    return await service.upload_document(
        db, chassis_id, document_type, document_number,
        issue_date, valid_until, issuing_authority, file, user.user_id,
    )


@router.patch('/documents/{doc_id}/verify', response_model=schemas.DocumentOut)
async def verify_document(
    doc_id: uuid.UUID,
    payload: schemas.DocumentVerify,
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(require_permission('YARD', 'edit')),
):
    return await service.verify_document(db, doc_id, payload, user.user_id)


@router.delete('/documents/{doc_id}')
async def delete_document(
    doc_id: uuid.UUID,
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'edit')),
):
    return await service.delete_document(db, doc_id)


# ── CUSTOMER-SUPPLIED PARTS ───────────────────────────

@router.post('/chassis/{chassis_id}/csp', response_model=schemas.CspOut, status_code=201)
async def create_csp(
    chassis_id: uuid.UUID,
    payload: schemas.CspCreate,
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(require_permission('YARD', 'create')),
):
    return await service.create_csp(db, chassis_id, payload, user.user_id)


@router.patch('/csp/{csp_id}', response_model=schemas.CspOut)
async def update_csp(
    csp_id: uuid.UUID,
    payload: schemas.CspStatusUpdate,
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(require_permission('YARD', 'edit')),
):
    return await service.update_csp(db, csp_id, payload, user.user_id)





# ── FACTORY LOCATION & STATION MANAGEMENT ROUTES ──────

@router.get('/locations', response_model=list[schemas.LocationOut])
async def list_locations(
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'view')),
):
    return await service.get_locations(db)


@router.post('/locations', response_model=schemas.LocationOut, status_code=201)
async def create_location(
    payload: schemas.LocationCreate,
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'create')),
):
    return await service.create_location(db, payload)


@router.put('/locations/{location_id}', response_model=schemas.LocationOut)
async def update_location(
    location_id: uuid.UUID,
    payload: schemas.LocationUpdate,
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'edit')),
):
    return await service.update_location(db, location_id, payload)


@router.get('/stations', response_model=list[schemas.StationDetailOut])
async def get_all_stations(
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'view')),
):
    return await service.get_all_stations(db)


@router.post('/stations', response_model=schemas.StationDetailOut, status_code=201)
async def create_station(
    payload: schemas.StationCreate,
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'create')),
):
    return await service.create_station(db, payload)


@router.put('/stations/{station_id}', response_model=schemas.StationDetailOut)
async def update_station(
    station_id: uuid.UUID,
    payload: schemas.StationUpdate,
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(require_permission('YARD', 'edit')),
):
    if user.role_code not in ('ADMIN', 'CLIENT_ADMIN', 'C_ADMIN'):
        raise HTTPException(status_code=403, detail="Only Admin and Client Admin can edit stations")
    return await service.update_station(db, station_id, payload)


@router.delete('/stations/{station_id}')
async def delete_station(
    station_id: uuid.UUID,
    db: AsyncSession = Depends(get_db),
    user: LoginUsers = Depends(require_permission('YARD', 'delete')),
):
    if user.role_code not in ('ADMIN', 'CLIENT_ADMIN', 'C_ADMIN'):
        raise HTTPException(status_code=403, detail="Only Admin and Client Admin can delete stations")
    return await service.delete_station(db, station_id)


@router.get('/stations/{station_id}/qa-items', response_model=list[schemas.StationQaItemOut])
async def get_station_qa_items(
    station_id: uuid.UUID,
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'view')),
):
    return await service.get_station_qa_items(db, station_id)


@router.post('/stations/qa-items', response_model=schemas.StationQaItemOut, status_code=201)
async def create_station_qa_item(
    payload: schemas.StationQaItemCreate,
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('YARD', 'create')),
):
    return await service.create_station_qa_item(db, payload)


# ── PRODUCTION REPORT ─────────────────────────────────────────

@router.get('/production-report')
async def get_production_report(
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('PRODUCTION', 'view')),
):
    """Full production report data (JSON) with dynamic special-feature columns."""
    return await production_report_service.get_production_report_data(db)


@router.get('/production-report/download')
async def download_production_report(
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('PRODUCTION', 'view')),
):
    """Download the production report as a styled .xlsx file."""
    buf = await production_report_service.generate_production_report_excel(db)
    today_str = date.today().strftime('%d-%b-%Y')
    filename = f'Production_Report_{today_str}.xlsx'
    return StreamingResponse(
        buf,
        media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        headers={'Content-Disposition': f'attachment; filename="{filename}"'},
    )


from pydantic import BaseModel
from typing import Optional

class ManualEntryUpdate(BaseModel):
    contractor_group: Optional[str] = None
    ac_make: Optional[str] = None
    interior_work: Optional[str] = None
    driver_request: Optional[str] = None
    document_pending: Optional[str] = None
    seat_fitting_pending: Optional[str] = None
    remark: Optional[str] = None


@router.put('/production-report/{chassis_id}/manual-entry')
async def update_manual_entry(
    chassis_id: uuid.UUID,
    payload: ManualEntryUpdate,
    db: AsyncSession = Depends(get_db),
    _=Depends(require_permission('PRODUCTION', 'edit')),
):
    """Create or update manual-entry fields for a chassis in the production report."""
    data = payload.model_dump(exclude_unset=True)
    return await production_report_service.upsert_manual_entry(db, chassis_id, data)

