"""
엑셀 내보내기 및 구매 배치 관리 API
"""
from fastapi import APIRouter, Depends, HTTPException, status, Response
from fastapi.responses import FileResponse
from sqlalchemy import text
from sqlalchemy.orm import Session
from typing import Optional, List, Dict, Any
from datetime import datetime
import json
import os
import openpyxl
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.utils import get_column_letter
import uuid

from ..database import get_db
from ..auth.middleware import get_current_user
from ..utils.logger import get_logger

logger = get_logger(__name__)

router = APIRouter(prefix="/export", tags=["Export Management"])

# 엑셀 파일 저장 경로
EXPORT_DIR = "exports"
os.makedirs(EXPORT_DIR, exist_ok=True)


def create_excel_from_materials(materials: List[Dict], batch_info: Dict) -> str:
    """
    자재 목록으로 엑셀 파일 생성
    """
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = batch_info.get("category", "자재목록")
    
    # 헤더 스타일
    header_fill = PatternFill(start_color="B8E6FF", end_color="B8E6FF", fill_type="solid")
    header_font = Font(bold=True, size=11)
    header_alignment = Alignment(horizontal="center", vertical="center")
    thin_border = Border(
        left=Side(style='thin'),
        right=Side(style='thin'),
        top=Side(style='thin'),
        bottom=Side(style='thin')
    )
    
    # 배치 정보 추가 (상단 3줄)
    ws.merge_cells('A1:J1')
    ws['A1'] = f"구매 배치: {batch_info.get('batch_no', 'N/A')}"
    ws['A1'].font = Font(bold=True, size=14)
    
    ws.merge_cells('A2:J2')
    ws['A2'] = f"프로젝트: {batch_info.get('job_no', '')} - {batch_info.get('job_name', '')}"
    
    ws.merge_cells('A3:J3')
    ws['A3'] = f"내보낸 날짜: {batch_info.get('export_date', datetime.now().strftime('%Y-%m-%d %H:%M'))}"
    
    # 빈 줄
    ws.append([])
    
    # 헤더 행
    headers = [
        "No.", "카테고리", "자재 설명", "크기", "스케줄/등급", 
        "재질", "수량", "단위", "추가요구", "사용자요구",
        "구매상태", "PR번호", "PO번호", "공급업체", "예정일"
    ]
    
    for col, header in enumerate(headers, 1):
        cell = ws.cell(row=5, column=col, value=header)
        cell.fill = header_fill
        cell.font = header_font
        cell.alignment = header_alignment
        cell.border = thin_border
    
    # 데이터 행
    row_num = 6
    for idx, material in enumerate(materials, 1):
        row_data = [
            idx,
            material.get("category", ""),
            material.get("description", ""),
            material.get("size", ""),
            material.get("schedule", ""),
            material.get("material_grade", ""),
            material.get("quantity", ""),
            material.get("unit", ""),
            material.get("additional_req", ""),
            material.get("user_requirement", ""),
            material.get("purchase_status", "pending"),
            material.get("purchase_request_no", ""),
            material.get("purchase_order_no", ""),
            material.get("vendor_name", ""),
            material.get("expected_date", "")
        ]
        
        for col, value in enumerate(row_data, 1):
            cell = ws.cell(row=row_num, column=col, value=value)
            cell.border = thin_border
            if col == 11:  # 구매상태 컬럼
                if value == "pending":
                    cell.fill = PatternFill(start_color="FFFFE0", end_color="FFFFE0", fill_type="solid")
                elif value == "requested":
                    cell.fill = PatternFill(start_color="FFE4B5", end_color="FFE4B5", fill_type="solid")
                elif value == "ordered":
                    cell.fill = PatternFill(start_color="ADD8E6", end_color="ADD8E6", fill_type="solid")
                elif value == "received":
                    cell.fill = PatternFill(start_color="90EE90", end_color="90EE90", fill_type="solid")
        
        row_num += 1
    
    # 열 너비 자동 조정
    for column in ws.columns:
        max_length = 0
        column_letter = get_column_letter(column[0].column)
        for cell in column:
            try:
                if len(str(cell.value)) > max_length:
                    max_length = len(str(cell.value))
            except:
                pass
        adjusted_width = min(max_length + 2, 50)
        ws.column_dimensions[column_letter].width = adjusted_width
    
    # 파일 저장
    file_name = f"batch_{batch_info.get('batch_no', uuid.uuid4().hex[:8])}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
    file_path = os.path.join(EXPORT_DIR, file_name)
    wb.save(file_path)
    
    return file_name


@router.post("/create-batch")
async def create_export_batch(
    file_id: int,
    job_no: Optional[str] = None,
    category: Optional[str] = None,
    materials: List[Dict] = [],
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    엑셀 내보내기 배치 생성 (자재 그룹화)
    """
    try:
        # 배치 번호 생성 (YYYYMMDD-XXX 형식)
        batch_date = datetime.now().strftime('%Y%m%d')
        
        # 오늘 생성된 배치 수 확인
        count_query = text("""
            SELECT COUNT(*) as count
            FROM excel_export_history
            WHERE DATE(export_date) = CURRENT_DATE
        """)
        count_result = db.execute(count_query).fetchone()
        batch_seq = (count_result.count + 1) if count_result else 1
        batch_no = f"{batch_date}-{str(batch_seq).zfill(3)}"
        
        # Job 정보 조회
        job_name = ""
        if job_no:
            job_query = text("SELECT job_name FROM jobs WHERE job_no = :job_no")
            job_result = db.execute(job_query, {"job_no": job_no}).fetchone()
            if job_result:
                job_name = job_result.job_name
        
        # 배치 정보
        batch_info = {
            "batch_no": batch_no,
            "job_no": job_no,
            "job_name": job_name,
            "category": category,
            "export_date": datetime.now().strftime('%Y-%m-%d %H:%M')
        }
        
        # 엑셀 파일 생성
        excel_file_name = create_excel_from_materials(materials, batch_info)
        
        # 내보내기 이력 저장
        insert_history = text("""
            INSERT INTO excel_export_history (
                file_id, job_no, exported_by, export_type, 
                category, material_count, file_name, notes
            ) VALUES (
                :file_id, :job_no, :exported_by, :export_type,
                :category, :material_count, :file_name, :notes
            ) RETURNING export_id
        """)
        
        result = db.execute(insert_history, {
            "file_id": file_id,
            "job_no": job_no,
            "exported_by": current_user.get("user_id"),
            "export_type": "batch",
            "category": category,
            "material_count": len(materials),
            "file_name": excel_file_name,
            "notes": f"배치번호: {batch_no}"
        })
        
        export_id = result.fetchone().export_id
        
        # 자재별 내보내기 기록
        material_ids = []
        for material in materials:
            material_id = material.get("id")
            if material_id:
                material_ids.append(material_id)
                
                insert_material = text("""
                    INSERT INTO exported_materials (
                        export_id, material_id, purchase_status,
                        quantity_exported
                    ) VALUES (
                        :export_id, :material_id, 'pending',
                        :quantity
                    )
                """)
                
                db.execute(insert_material, {
                    "export_id": export_id,
                    "material_id": material_id,
                    "quantity": material.get("quantity", 0)
                })
        
        db.commit()
        
        logger.info(f"Export batch created: {batch_no} with {len(materials)} materials")
        
        return {
            "success": True,
            "batch_no": batch_no,
            "export_id": export_id,
            "file_name": excel_file_name,
            "material_count": len(materials),
            "message": f"배치 {batch_no}가 생성되었습니다"
        }
        
    except Exception as e:
        db.rollback()
        logger.error(f"Failed to create export batch: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"배치 생성 실패: {str(e)}"
        )


@router.get("/batches")
async def get_export_batches(
    file_id: Optional[int] = None,
    job_no: Optional[str] = None,
    status: Optional[str] = None,
    limit: int = 50,
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    내보내기 배치 목록 조회
    """
    try:
        query = text("""
            SELECT 
                eeh.export_id,
                eeh.file_id,
                eeh.job_no,
                eeh.export_date,
                eeh.category,
                eeh.material_count,
                eeh.file_name,
                eeh.notes,
                u.name as exported_by,
                j.job_name,
                f.original_filename,
                -- 상태별 집계
                COUNT(DISTINCT em.material_id) as total_materials,
                COUNT(DISTINCT CASE WHEN em.purchase_status = 'pending' THEN em.material_id END) as pending_count,
                COUNT(DISTINCT CASE WHEN em.purchase_status = 'requested' THEN em.material_id END) as requested_count,
                COUNT(DISTINCT CASE WHEN em.purchase_status = 'ordered' THEN em.material_id END) as ordered_count,
                COUNT(DISTINCT CASE WHEN em.purchase_status = 'received' THEN em.material_id END) as received_count,
                -- 전체 상태 계산
                CASE 
                    WHEN COUNT(DISTINCT em.material_id) = COUNT(DISTINCT CASE WHEN em.purchase_status = 'received' THEN em.material_id END) 
                        THEN 'completed'
                    WHEN COUNT(DISTINCT CASE WHEN em.purchase_status = 'ordered' THEN em.material_id END) > 0 
                        THEN 'in_progress'
                    WHEN COUNT(DISTINCT CASE WHEN em.purchase_status = 'requested' THEN em.material_id END) > 0 
                        THEN 'requested'
                    ELSE 'pending'
                END as batch_status
            FROM excel_export_history eeh
            LEFT JOIN users u ON eeh.exported_by = u.user_id
            LEFT JOIN jobs j ON eeh.job_no = j.job_no
            LEFT JOIN files f ON eeh.file_id = f.id
            LEFT JOIN exported_materials em ON eeh.export_id = em.export_id
            WHERE eeh.export_type = 'batch'
                AND (:file_id IS NULL OR eeh.file_id = :file_id)
                AND (:job_no IS NULL OR eeh.job_no = :job_no)
            GROUP BY 
                eeh.export_id, eeh.file_id, eeh.job_no, eeh.export_date,
                eeh.category, eeh.material_count, eeh.file_name, eeh.notes,
                u.name, j.job_name, f.original_filename
            HAVING (:status IS NULL OR 
                CASE 
                    WHEN COUNT(DISTINCT em.material_id) = COUNT(DISTINCT CASE WHEN em.purchase_status = 'received' THEN em.material_id END) 
                        THEN 'completed'
                    WHEN COUNT(DISTINCT CASE WHEN em.purchase_status = 'ordered' THEN em.material_id END) > 0 
                        THEN 'in_progress'
                    WHEN COUNT(DISTINCT CASE WHEN em.purchase_status = 'requested' THEN em.material_id END) > 0 
                        THEN 'requested'
                    ELSE 'pending'
                END = :status)
            ORDER BY eeh.export_date DESC
            LIMIT :limit
        """)
        
        results = db.execute(query, {
            "file_id": file_id,
            "job_no": job_no,
            "status": status,
            "limit": limit
        }).fetchall()
        
        batches = []
        for row in results:
            # 배치 번호 추출 (notes에서)
            batch_no = ""
            if row.notes and "배치번호:" in row.notes:
                batch_no = row.notes.split("배치번호:")[1].strip()
            
            batches.append({
                "export_id": row.export_id,
                "batch_no": batch_no,
                "file_id": row.file_id,
                "job_no": row.job_no,
                "job_name": row.job_name,
                "export_date": row.export_date.isoformat() if row.export_date else None,
                "category": row.category,
                "material_count": row.total_materials,
                "file_name": row.file_name,
                "exported_by": row.exported_by,
                "source_file": row.original_filename,
                "batch_status": row.batch_status,
                "status_detail": {
                    "pending": row.pending_count,
                    "requested": row.requested_count,
                    "ordered": row.ordered_count,
                    "received": row.received_count,
                    "total": row.total_materials
                }
            })
        
        return {
            "success": True,
            "batches": batches,
            "count": len(batches)
        }
        
    except Exception as e:
        logger.error(f"Failed to get export batches: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"배치 목록 조회 실패: {str(e)}"
        )


@router.get("/batch/{export_id}/materials")
async def get_batch_materials(
    export_id: int,
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    배치에 포함된 자재 목록 조회
    """
    try:
        query = text("""
            SELECT 
                em.id as exported_material_id,
                em.material_id,
                m.original_description,
                m.classified_category,
                m.size_inch,
                m.schedule,
                m.material_grade,
                m.quantity,
                m.unit,
                em.purchase_status,
                em.purchase_request_no,
                em.purchase_order_no,
                em.vendor_name,
                em.expected_date,
                em.quantity_ordered,
                em.quantity_received,
                em.unit_price,
                em.total_price,
                em.notes,
                ur.requirement as user_requirement
            FROM exported_materials em
            JOIN materials m ON em.material_id = m.id
            LEFT JOIN user_requirements ur ON m.id = ur.material_id
            WHERE em.export_id = :export_id
            ORDER BY m.classified_category, m.original_description
        """)
        
        results = db.execute(query, {"export_id": export_id}).fetchall()
        
        materials = []
        for row in results:
            materials.append({
                "exported_material_id": row.exported_material_id,
                "material_id": row.material_id,
                "description": row.original_description,
                "category": row.classified_category,
                "size": row.size_inch,
                "schedule": row.schedule,
                "material_grade": row.material_grade,
                "quantity": row.quantity,
                "unit": row.unit,
                "user_requirement": row.user_requirement,
                "purchase_status": row.purchase_status,
                "purchase_request_no": row.purchase_request_no,
                "purchase_order_no": row.purchase_order_no,
                "vendor_name": row.vendor_name,
                "expected_date": row.expected_date.isoformat() if row.expected_date else None,
                "quantity_ordered": row.quantity_ordered,
                "quantity_received": row.quantity_received,
                "unit_price": float(row.unit_price) if row.unit_price else None,
                "total_price": float(row.total_price) if row.total_price else None,
                "notes": row.notes
            })
        
        return {
            "success": True,
            "materials": materials,
            "count": len(materials)
        }
        
    except Exception as e:
        logger.error(f"Failed to get batch materials: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"배치 자재 조회 실패: {str(e)}"
        )


@router.get("/batch/{export_id}/download")
async def download_batch_excel(
    export_id: int,
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    저장된 배치 엑셀 파일 다운로드
    """
    try:
        # 배치 정보 조회
        query = text("""
            SELECT file_name, notes
            FROM excel_export_history
            WHERE export_id = :export_id
        """)
        result = db.execute(query, {"export_id": export_id}).fetchone()
        
        if not result:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="배치를 찾을 수 없습니다"
            )
        
        file_path = os.path.join(EXPORT_DIR, result.file_name)
        
        if not os.path.exists(file_path):
            # 파일이 없으면 재생성
            materials = await get_batch_materials(export_id, current_user, db)
            
            batch_no = ""
            if result.notes and "배치번호:" in result.notes:
                batch_no = result.notes.split("배치번호:")[1].strip()
            
            batch_info = {
                "batch_no": batch_no,
                "export_date": datetime.now().strftime('%Y-%m-%d %H:%M')
            }
            
            file_name = create_excel_from_materials(materials["materials"], batch_info)
            file_path = os.path.join(EXPORT_DIR, file_name)
            
            # DB 업데이트
            update_query = text("""
                UPDATE excel_export_history
                SET file_name = :file_name
                WHERE export_id = :export_id
            """)
            db.execute(update_query, {
                "file_name": file_name,
                "export_id": export_id
            })
            db.commit()
        
        return FileResponse(
            path=file_path,
            filename=result.file_name,
            media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
        )
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to download batch excel: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"엑셀 다운로드 실패: {str(e)}"
        )


@router.patch("/batch/{export_id}/status")
async def update_batch_status(
    export_id: int,
    status: str,
    purchase_request_no: Optional[str] = None,
    purchase_order_no: Optional[str] = None,
    vendor_name: Optional[str] = None,
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_db)
):
    """
    배치 전체 상태 일괄 업데이트
    """
    try:
        # 배치의 모든 자재 상태 업데이트
        update_query = text("""
            UPDATE exported_materials
            SET 
                purchase_status = :status,
                purchase_request_no = COALESCE(:pr_no, purchase_request_no),
                purchase_order_no = COALESCE(:po_no, purchase_order_no),
                vendor_name = COALESCE(:vendor, vendor_name),
                updated_by = :updated_by,
                requested_date = CASE WHEN :status = 'requested' THEN CURRENT_TIMESTAMP ELSE requested_date END,
                ordered_date = CASE WHEN :status = 'ordered' THEN CURRENT_TIMESTAMP ELSE ordered_date END,
                received_date = CASE WHEN :status = 'received' THEN CURRENT_TIMESTAMP ELSE received_date END
            WHERE export_id = :export_id
        """)
        
        result = db.execute(update_query, {
            "export_id": export_id,
            "status": status,
            "pr_no": purchase_request_no,
            "po_no": purchase_order_no,
            "vendor": vendor_name,
            "updated_by": current_user.get("user_id")
        })
        
        # 이력 기록
        history_query = text("""
            INSERT INTO purchase_status_history (
                exported_material_id, material_id, 
                previous_status, new_status, 
                changed_by, reason
            )
            SELECT 
                em.id, em.material_id,
                em.purchase_status, :new_status,
                :changed_by, :reason
            FROM exported_materials em
            WHERE em.export_id = :export_id
        """)
        
        db.execute(history_query, {
            "export_id": export_id,
            "new_status": status,
            "changed_by": current_user.get("user_id"),
            "reason": f"배치 일괄 업데이트"
        })
        
        db.commit()
        
        logger.info(f"Batch {export_id} status updated to {status}")
        
        return {
            "success": True,
            "message": f"배치의 모든 자재가 {status} 상태로 변경되었습니다",
            "updated_count": result.rowcount
        }
        
    except Exception as e:
        db.rollback()
        logger.error(f"Failed to update batch status: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"배치 상태 업데이트 실패: {str(e)}"
        )
