"""
구매 관리 API
- 구매 품목 생성/조회
- 구매 수량 계산
- 리비전 비교
"""

from fastapi import APIRouter, Depends, HTTPException, Query, Request
from sqlalchemy.orm import Session
from sqlalchemy import text
from typing import List, Optional
from pydantic import BaseModel
import json
from datetime import datetime

from ..database import get_db
from ..services.purchase_calculator import (
    generate_purchase_items_from_materials,
    save_purchase_items_to_db,
    calculate_pipe_purchase_quantity,
    calculate_standard_purchase_quantity
)

router = APIRouter(prefix="/purchase", tags=["purchase"])

# Pydantic 모델 (최적화된 구조)
class PurchaseItemMinimal(BaseModel):
    """구매 확정용 최소 필수 데이터"""
    item_code: str
    category: str
    specification: str
    size: str = ""
    material: str = ""
    bom_quantity: float
    calculated_qty: float
    unit: str = "EA"
    safety_factor: float = 1.0

class PurchaseConfirmRequest(BaseModel):
    job_no: str
    file_id: int
    bom_name: Optional[str] = None  # 선택적 필드로 변경
    revision: str
    purchase_items: List[PurchaseItemMinimal]  # 최적화된 구조 사용
    confirmed_at: str
    confirmed_by: str

@router.get("/items/calculate")
async def calculate_purchase_items(
    job_no: str = Query(..., description="Job 번호"),
    revision: str = Query("Rev.0", description="리비전"),
    file_id: Optional[int] = Query(None, description="파일 ID (선택사항)"),
    db: Session = Depends(get_db)
):
    """
    구매 품목 계산 (실시간)
    - 자재 데이터로부터 구매 품목 생성
    - 수량 계산 (파이프 절단손실 포함)
    """
    try:
        # 1. 파일 ID 조회 (job_no, revision으로)
        if not file_id:
            file_query = text("""
                SELECT id FROM files 
                WHERE job_no = :job_no AND revision = :revision AND is_active = TRUE
                ORDER BY updated_at DESC
                LIMIT 1
            """)
            file_result = db.execute(file_query, {"job_no": job_no, "revision": revision}).fetchone()
            if not file_result:
                raise HTTPException(status_code=404, detail=f"Job {job_no} {revision}에 해당하는 파일을 찾을 수 없습니다")
            file_id = file_result[0]
        
        # 2. 구매 품목 생성
        purchase_items = generate_purchase_items_from_materials(db, file_id, job_no, revision)
        
        return {
            "success": True,
            "job_no": job_no,
            "revision": revision,
            "file_id": file_id,
            "items": purchase_items,
            "total_items": len(purchase_items)
        }
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"구매 품목 계산 실패: {str(e)}")

@router.post("/confirm")
async def confirm_purchase_quantities(
    request: PurchaseConfirmRequest,
    db: Session = Depends(get_db)
):
    """
    구매 수량 확정
    - 계산된 구매 수량을 확정 상태로 저장
    - 자재별 확정 수량 및 상태 업데이트
    - 리비전 비교를 위한 기준 데이터 생성
    """
    try:
        # 1. 기존 확정 데이터 확인 및 업데이트 또는 삽입
        existing_query = text("""
            SELECT id FROM purchase_confirmations 
            WHERE file_id = :file_id
        """)
        existing_result = db.execute(existing_query, {"file_id": request.file_id}).fetchone()
        
        if existing_result:
            # 기존 데이터 업데이트
            confirmation_id = existing_result[0]
            update_query = text("""
                UPDATE purchase_confirmations 
                SET job_no = :job_no,
                    bom_name = :bom_name,
                    revision = :revision,
                    confirmed_at = :confirmed_at,
                    confirmed_by = :confirmed_by,
                    is_active = TRUE,
                    updated_at = CURRENT_TIMESTAMP
                WHERE id = :confirmation_id
            """)
            db.execute(update_query, {
                "confirmation_id": confirmation_id,
                "job_no": request.job_no,
                "bom_name": request.bom_name or f"{request.job_no}_{request.revision}",  # 기본값 제공
                "revision": request.revision,
                "confirmed_at": request.confirmed_at,
                "confirmed_by": request.confirmed_by
            })
            
            # 기존 확정 품목들 삭제
            delete_items_query = text("""
                DELETE FROM confirmed_purchase_items 
                WHERE confirmation_id = :confirmation_id
            """)
            db.execute(delete_items_query, {"confirmation_id": confirmation_id})
        else:
            # 새로운 확정 데이터 삽입
            confirm_query = text("""
                INSERT INTO purchase_confirmations (
                    job_no, file_id, bom_name, revision, 
                    confirmed_at, confirmed_by, is_active, created_at
                ) VALUES (
                    :job_no, :file_id, :bom_name, :revision,
                    :confirmed_at, :confirmed_by, TRUE, CURRENT_TIMESTAMP
                ) RETURNING id
            """)
            
            confirm_result = db.execute(confirm_query, {
                "job_no": request.job_no,
                "file_id": request.file_id,
                "bom_name": request.bom_name or f"{request.job_no}_{request.revision}",  # 기본값 제공
                "revision": request.revision,
                "confirmed_at": request.confirmed_at,
                "confirmed_by": request.confirmed_by
            })
            
            confirmation_id = confirm_result.fetchone()[0]
        
        # 3. 확정된 구매 품목들 저장
        saved_items = 0
        for item in request.purchase_items:
            item_query = text("""
                INSERT INTO confirmed_purchase_items (
                    confirmation_id, item_code, category, specification, 
                    size, material, bom_quantity, calculated_qty, 
                    unit, safety_factor, created_at
                ) VALUES (
                    :confirmation_id, :item_code, :category, :specification,
                    :size, :material, :bom_quantity, :calculated_qty,
                    :unit, :safety_factor, CURRENT_TIMESTAMP
                )
            """)
            
            db.execute(item_query, {
                "confirmation_id": confirmation_id,
                "item_code": item.item_code or f"{item.category}-{saved_items+1}",
                "category": item.category,
                "specification": item.specification,
                "size": item.size or "",
                "material": item.material or "",
                "bom_quantity": item.bom_quantity,
                "calculated_qty": item.calculated_qty,
                "unit": item.unit,
                "safety_factor": item.safety_factor
            })
            saved_items += 1
        
        # 4. 파일 상태를 확정으로 업데이트
        file_update_query = text("""
            UPDATE files 
            SET purchase_confirmed = TRUE, 
                confirmed_at = :confirmed_at,
                confirmed_by = :confirmed_by,
                updated_at = CURRENT_TIMESTAMP
            WHERE id = :file_id
        """)
        
        db.execute(file_update_query, {
            "file_id": request.file_id,
            "confirmed_at": request.confirmed_at,
            "confirmed_by": request.confirmed_by
        })
        
        db.commit()
        
        return {
            "success": True,
            "message": "구매 수량이 성공적으로 확정되었습니다",
            "confirmation_id": confirmation_id,
            "confirmed_items": saved_items,
            "job_no": request.job_no,
            "revision": request.revision,
            "confirmed_at": request.confirmed_at,
            "confirmed_by": request.confirmed_by
        }
        
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=f"구매 수량 확정 실패: {str(e)}")

@router.post("/items/save")
async def save_purchase_items(
    job_no: str,
    revision: str,
    file_id: int,
    db: Session = Depends(get_db)
):
    """
    구매 품목을 데이터베이스에 저장
    """
    try:
        # 1. 구매 품목 생성
        purchase_items = generate_purchase_items_from_materials(db, file_id, job_no, revision)
        
        # 2. 데이터베이스에 저장
        saved_ids = save_purchase_items_to_db(db, purchase_items)
        
        return {
            "success": True,
            "message": f"{len(saved_ids)}개 구매 품목이 저장되었습니다",
            "saved_items": len(saved_ids),
            "item_ids": saved_ids
        }
        
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=f"구매 품목 저장 실패: {str(e)}")

@router.get("/items")
async def get_purchase_items(
    job_no: str = Query(..., description="Job 번호"),
    revision: str = Query("Rev.0", description="리비전"),
    category: Optional[str] = Query(None, description="카테고리 필터"),
    db: Session = Depends(get_db)
):
    """
    저장된 구매 품목 조회
    """
    try:
        query = text("""
            SELECT pi.*, 
                   COUNT(mpm.material_id) as material_count,
                   SUM(m.quantity) as total_material_quantity
            FROM purchase_items pi
            LEFT JOIN material_purchase_mapping mpm ON pi.id = mpm.purchase_item_id
            LEFT JOIN materials m ON mpm.material_id = m.id
            WHERE pi.job_no = :job_no AND pi.revision = :revision AND pi.is_active = TRUE
        """)
        
        params = {"job_no": job_no, "revision": revision}
        
        if category:
            query = text(str(query) + " AND pi.category = :category")
            params["category"] = category
        
        query = text(str(query) + """
            GROUP BY pi.id
            ORDER BY pi.category, pi.specification
        """)
        
        result = db.execute(query, params)
        items = result.fetchall()
        
        return {
            "success": True,
            "job_no": job_no,
            "revision": revision,
            "items": [dict(item) for item in items],
            "total_items": len(items)
        }
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"구매 품목 조회 실패: {str(e)}")

@router.patch("/items/{item_id}")
async def update_purchase_item(
    item_id: int,
    safety_factor: Optional[float] = None,
    calculated_qty: Optional[float] = None,
    minimum_order_qty: Optional[float] = None,
    db: Session = Depends(get_db)
):
    """
    구매 품목 수정 (수량 조정)
    """
    try:
        update_fields = []
        params = {"item_id": item_id}
        
        if safety_factor is not None:
            update_fields.append("safety_factor = :safety_factor")
            params["safety_factor"] = safety_factor
        
        if calculated_qty is not None:
            update_fields.append("calculated_qty = :calculated_qty")
            params["calculated_qty"] = calculated_qty
        
        if minimum_order_qty is not None:
            update_fields.append("minimum_order_qty = :minimum_order_qty")
            params["minimum_order_qty"] = minimum_order_qty
        
        if not update_fields:
            raise HTTPException(status_code=400, detail="수정할 필드가 없습니다")
        
        update_fields.append("updated_at = CURRENT_TIMESTAMP")
        
        query = text(f"""
            UPDATE purchase_items 
            SET {', '.join(update_fields)}
            WHERE id = :item_id
            RETURNING id, calculated_qty, safety_factor
        """)
        
        result = db.execute(query, params)
        updated_item = result.fetchone()
        
        if not updated_item:
            raise HTTPException(status_code=404, detail="구매 품목을 찾을 수 없습니다")
        
        db.commit()
        
        return {
            "success": True,
            "message": "구매 품목이 수정되었습니다",
            "item": dict(updated_item)
        }
        
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=f"구매 품목 수정 실패: {str(e)}")

@router.get("/revision-diff")
async def get_revision_diff(
    job_no: str = Query(..., description="Job 번호"),
    current_revision: str = Query(..., description="현재 리비전"),
    previous_revision: str = Query(..., description="이전 리비전"),
    db: Session = Depends(get_db)
):
    """
    리비전간 구매 수량 차이 계산
    """
    try:
        # 1. 이전 리비전 구매 품목 조회
        prev_query = text("""
            SELECT item_code, category, specification, calculated_qty, bom_quantity
            FROM purchase_items
            WHERE job_no = :job_no AND revision = :prev_revision AND is_active = TRUE
        """)
        prev_items = db.execute(prev_query, {
            "job_no": job_no, 
            "prev_revision": previous_revision
        }).fetchall()
        
        # 2. 현재 리비전 구매 품목 조회
        curr_query = text("""
            SELECT item_code, category, specification, calculated_qty, bom_quantity
            FROM purchase_items
            WHERE job_no = :job_no AND revision = :curr_revision AND is_active = TRUE
        """)
        curr_items = db.execute(curr_query, {
            "job_no": job_no,
            "curr_revision": current_revision
        }).fetchall()
        
        # 3. 차이 계산
        prev_dict = {item.item_code: dict(item) for item in prev_items}
        curr_dict = {item.item_code: dict(item) for item in curr_items}
        
        changes = []
        added_items = 0
        modified_items = 0
        
        # 현재 리비전에서 추가되거나 변경된 항목
        for item_code, curr_item in curr_dict.items():
            if item_code not in prev_dict:
                # 새로 추가된 품목
                changes.append({
                    "item_code": item_code,
                    "change_type": "ADDED",
                    "specification": curr_item["specification"],
                    "previous_qty": 0,
                    "current_qty": curr_item["calculated_qty"],
                    "qty_diff": curr_item["calculated_qty"],
                    "additional_needed": curr_item["calculated_qty"]
                })
                added_items += 1
            else:
                prev_item = prev_dict[item_code]
                qty_diff = curr_item["calculated_qty"] - prev_item["calculated_qty"]
                
                if abs(qty_diff) > 0.001:  # 수량 변경
                    changes.append({
                        "item_code": item_code,
                        "change_type": "MODIFIED",
                        "specification": curr_item["specification"],
                        "previous_qty": prev_item["calculated_qty"],
                        "current_qty": curr_item["calculated_qty"],
                        "qty_diff": qty_diff,
                        "additional_needed": max(qty_diff, 0)  # 증가한 경우만 추가 구매
                    })
                    modified_items += 1
        
        # 삭제된 품목 (현재 리비전에 없는 항목)
        removed_items = 0
        for item_code, prev_item in prev_dict.items():
            if item_code not in curr_dict:
                changes.append({
                    "item_code": item_code,
                    "change_type": "REMOVED",
                    "specification": prev_item["specification"],
                    "previous_qty": prev_item["calculated_qty"],
                    "current_qty": 0,
                    "qty_diff": -prev_item["calculated_qty"],
                    "additional_needed": 0
                })
                removed_items += 1
        
        # 요약 정보
        total_additional_needed = sum(
            change["additional_needed"] for change in changes 
            if change["additional_needed"] > 0
        )
        
        has_changes = len(changes) > 0
        
        summary = f"추가: {added_items}개, 변경: {modified_items}개, 삭제: {removed_items}개"
        if total_additional_needed > 0:
            summary += f" (추가 구매 필요: {total_additional_needed:.1f})"
        
        return {
            "success": True,
            "job_no": job_no,
            "previous_revision": previous_revision,
            "current_revision": current_revision,
            "comparison": {
                "has_changes": has_changes,
                "summary": summary,
                "added_items": added_items,
                "modified_items": modified_items,
                "removed_items": removed_items,
                "total_additional_needed": total_additional_needed,
                "changes": changes
            }
        }
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"리비전 비교 실패: {str(e)}")

@router.post("/orders/create")
async def create_purchase_order(
    job_no: str,
    revision: str,
    items: List[dict],
    supplier_name: Optional[str] = None,
    required_date: Optional[str] = None,
    db: Session = Depends(get_db)
):
    """
    구매 주문 생성
    """
    try:
        from datetime import datetime, date
        
        # 1. 주문 번호 생성
        order_no = f"PO-{job_no}-{revision}-{datetime.now().strftime('%Y%m%d')}"
        
        # 2. 구매 주문 생성
        order_query = text("""
            INSERT INTO purchase_orders (
                order_no, job_no, revision, status, order_date, required_date,
                supplier_name, created_by
            ) VALUES (
                :order_no, :job_no, :revision, 'DRAFT', CURRENT_DATE, :required_date,
                :supplier_name, 'system'
            ) RETURNING id
        """)
        
        order_result = db.execute(order_query, {
            "order_no": order_no,
            "job_no": job_no,
            "revision": revision,
            "required_date": required_date,
            "supplier_name": supplier_name
        })
        
        order_id = order_result.fetchone()[0]
        
        # 3. 주문 상세 항목 생성
        total_amount = 0
        for item in items:
            item_query = text("""
                INSERT INTO purchase_order_items (
                    purchase_order_id, purchase_item_id, ordered_quantity, required_date
                ) VALUES (
                    :order_id, :item_id, :quantity, :required_date
                )
            """)
            
            db.execute(item_query, {
                "order_id": order_id,
                "item_id": item["purchase_item_id"],
                "quantity": item["ordered_quantity"],
                "required_date": required_date
            })
        
        db.commit()
        
        return {
            "success": True,
            "message": "구매 주문이 생성되었습니다",
            "order_no": order_no,
            "order_id": order_id,
            "items_count": len(items)
        }
        
    except Exception as e:
        db.rollback()
        raise HTTPException(status_code=500, detail=f"구매 주문 생성 실패: {str(e)}")

@router.get("/orders")
async def get_purchase_orders(
    job_no: Optional[str] = Query(None, description="Job 번호"),
    status: Optional[str] = Query(None, description="주문 상태"),
    db: Session = Depends(get_db)
):
    """
    구매 주문 목록 조회
    """
    try:
        query = text("""
            SELECT po.*, 
                   COUNT(poi.id) as items_count,
                   SUM(poi.ordered_quantity) as total_quantity
            FROM purchase_orders po
            LEFT JOIN purchase_order_items poi ON po.id = poi.purchase_order_id
            WHERE 1=1
        """)
        
        params = {}
        
        if job_no:
            query = text(str(query) + " AND po.job_no = :job_no")
            params["job_no"] = job_no
        
        if status:
            query = text(str(query) + " AND po.status = :status")
            params["status"] = status
        
        query = text(str(query) + """
            GROUP BY po.id
            ORDER BY po.created_at DESC
        """)
        
        result = db.execute(query, params)
        orders = result.fetchall()
        
        return {
            "success": True,
            "orders": [dict(order) for order in orders],
            "total_orders": len(orders)
        }
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"구매 주문 조회 실패: {str(e)}") 