"""
PIPE 리비전 관리 API 라우터

Cutting Plan 전/후 리비전 처리 및 비교 기능
"""

import logging
from typing import Dict, List, Optional, Any
from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from pydantic import BaseModel

from ..database import get_db
from ..services.pipe_revision_service import get_pipe_revision_service, PipeRevisionService
from ..models import PipeRevisionComparison, PipeRevisionChange

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/pipe-revision", tags=["pipe-revision"])


# Pydantic 모델들
class RevisionStatusRequest(BaseModel):
    job_no: str
    new_file_id: int


class PreRevisionRequest(BaseModel):
    job_no: str
    new_file_id: int


class PostRevisionRequest(BaseModel):
    job_no: str
    new_file_id: int


class RevisionStatusResponse(BaseModel):
    revision_type: str
    requires_action: bool
    message: str
    previous_file_id: Optional[int] = None


class PreRevisionResponse(BaseModel):
    status: str
    revision_type: str
    deleted_items: int
    new_pipe_materials: int
    message: str
    next_action: str
    pipe_materials: List[Dict[str, Any]]


class PostRevisionResponse(BaseModel):
    status: str
    revision_type: str
    comparison_id: int
    summary: Dict[str, Any]
    changed_drawings: List[Dict[str, Any]]
    unchanged_drawings: List[Dict[str, Any]]
    message: str
    next_action: str


@router.post("/check-status", response_model=RevisionStatusResponse)
async def check_revision_status(
    request: RevisionStatusRequest,
    db: Session = Depends(get_db)
):
    """
    PIPE 리비전 상태 확인
    - 리비전 유형 판단 (pre/post cutting plan)
    - 필요한 처리 방식 결정
    """
    try:
        service = get_pipe_revision_service(db)
        result = service.check_revision_status(request.job_no, request.new_file_id)
        
        return RevisionStatusResponse(**result)
        
    except Exception as e:
        logger.error(f"Failed to check pipe revision status: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"리비전 상태 확인 실패: {str(e)}"
        )


@router.post("/handle-pre-cutting-plan", response_model=PreRevisionResponse)
async def handle_pre_cutting_plan_revision(
    request: PreRevisionRequest,
    db: Session = Depends(get_db)
):
    """
    Cutting Plan 작성 전 리비전 처리
    - 기존 PIPE 데이터 삭제
    - 새 BOM 데이터로 초기화
    """
    try:
        service = get_pipe_revision_service(db)
        result = service.handle_pre_cutting_plan_revision(request.job_no, request.new_file_id)
        
        if result["status"] != "success":
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=result["message"]
            )
        
        return PreRevisionResponse(**result)
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to handle pre-cutting-plan revision: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Cutting Plan 작성 전 리비전 처리 실패: {str(e)}"
        )


@router.post("/handle-post-cutting-plan", response_model=PostRevisionResponse)
async def handle_post_cutting_plan_revision(
    request: PostRevisionRequest,
    db: Session = Depends(get_db)
):
    """
    Cutting Plan 작성 후 리비전 처리
    - 기존 Cutting Plan과 신규 BOM 비교
    - 변경사항 상세 분석
    """
    try:
        service = get_pipe_revision_service(db)
        result = service.handle_post_cutting_plan_revision(request.job_no, request.new_file_id)
        
        if result["status"] != "success":
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=result["message"]
            )
        
        return PostRevisionResponse(**result)
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to handle post-cutting-plan revision: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"Cutting Plan 작성 후 리비전 처리 실패: {str(e)}"
        )


@router.get("/comparison/{comparison_id}")
async def get_revision_comparison(
    comparison_id: int,
    db: Session = Depends(get_db)
):
    """
    리비전 비교 결과 상세 조회
    """
    try:
        # 비교 결과 조회
        comparison = db.query(PipeRevisionComparison).filter(
            PipeRevisionComparison.id == comparison_id
        ).first()
        
        if not comparison:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="비교 결과를 찾을 수 없습니다."
            )
        
        # 상세 변경사항 조회
        changes = db.query(PipeRevisionChange).filter(
            PipeRevisionChange.comparison_id == comparison_id
        ).all()
        
        # 도면별로 변경사항 그룹화
        changes_by_drawing = {}
        for change in changes:
            drawing = change.drawing_name
            if drawing not in changes_by_drawing:
                changes_by_drawing[drawing] = []
            
            changes_by_drawing[drawing].append({
                "id": change.id,
                "change_type": change.change_type,
                "old_data": {
                    "line_no": change.old_line_no,
                    "material_grade": change.old_material_grade,
                    "schedule_spec": change.old_schedule_spec,
                    "nominal_size": change.old_nominal_size,
                    "length_mm": change.old_length_mm,
                    "end_preparation": change.old_end_preparation
                } if change.old_line_no else None,
                "new_data": {
                    "line_no": change.new_line_no,
                    "material_grade": change.new_material_grade,
                    "schedule_spec": change.new_schedule_spec,
                    "nominal_size": change.new_nominal_size,
                    "length_mm": change.new_length_mm,
                    "end_preparation": change.new_end_preparation
                } if change.new_line_no else None,
                "change_reason": change.change_reason
            })
        
        return {
            "comparison_id": comparison.id,
            "job_no": comparison.job_no,
            "comparison_date": comparison.comparison_date,
            "summary": {
                "total_drawings": comparison.total_drawings,
                "changed_drawings": comparison.changed_drawings,
                "unchanged_drawings": comparison.unchanged_drawings,
                "total_segments": comparison.total_segments,
                "added_segments": comparison.added_segments,
                "removed_segments": comparison.removed_segments,
                "modified_segments": comparison.modified_segments,
                "unchanged_segments": comparison.unchanged_segments
            },
            "changes_by_drawing": changes_by_drawing,
            "is_applied": comparison.is_applied,
            "applied_at": comparison.applied_at,
            "applied_by": comparison.applied_by
        }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to get revision comparison: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"리비전 비교 결과 조회 실패: {str(e)}"
        )


@router.post("/comparison/{comparison_id}/apply")
async def apply_revision_changes(
    comparison_id: int,
    db: Session = Depends(get_db)
):
    """
    리비전 변경사항 적용
    """
    try:
        # 비교 결과 조회
        comparison = db.query(PipeRevisionComparison).filter(
            PipeRevisionComparison.id == comparison_id
        ).first()
        
        if not comparison:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="비교 결과를 찾을 수 없습니다."
            )
        
        if comparison.is_applied:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail="이미 적용된 리비전입니다."
            )
        
        # 적용 상태 업데이트
        comparison.is_applied = True
        comparison.applied_at = datetime.utcnow()
        comparison.applied_by = "system"  # 추후 사용자 정보로 변경
        
        db.commit()
        
        return {
            "status": "success",
            "message": "리비전 변경사항이 적용되었습니다.",
            "comparison_id": comparison_id,
            "applied_at": comparison.applied_at
        }
        
    except HTTPException:
        raise
    except Exception as e:
        db.rollback()
        logger.error(f"Failed to apply revision changes: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"리비전 변경사항 적용 실패: {str(e)}"
        )


@router.get("/job/{job_no}/history")
async def get_revision_history(
    job_no: str,
    db: Session = Depends(get_db)
):
    """
    작업별 PIPE 리비전 이력 조회
    """
    try:
        comparisons = db.query(PipeRevisionComparison).filter(
            PipeRevisionComparison.job_no == job_no
        ).order_by(PipeRevisionComparison.comparison_date.desc()).all()
        
        history = []
        for comp in comparisons:
            history.append({
                "comparison_id": comp.id,
                "comparison_date": comp.comparison_date,
                "summary": {
                    "total_drawings": comp.total_drawings,
                    "changed_drawings": comp.changed_drawings,
                    "total_segments": comp.total_segments,
                    "added_segments": comp.added_segments,
                    "removed_segments": comp.removed_segments,
                    "modified_segments": comp.modified_segments
                },
                "is_applied": comp.is_applied,
                "applied_at": comp.applied_at,
                "applied_by": comp.applied_by,
                "created_by": comp.created_by
            })
        
        return {
            "job_no": job_no,
            "total_revisions": len(history),
            "history": history
        }
        
    except Exception as e:
        logger.error(f"Failed to get revision history: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"리비전 이력 조회 실패: {str(e)}"
        )


@router.get("/comparison/{comparison_id}/purchase-impact")
async def get_purchase_impact(
    comparison_id: int,
    db: Session = Depends(get_db)
):
    """
    리비전이 구매량에 미치는 영향 분석
    """
    try:
        # 비교 결과 조회
        comparison = db.query(PipeRevisionComparison).filter(
            PipeRevisionComparison.id == comparison_id
        ).first()
        
        if not comparison:
            raise HTTPException(
                status_code=status.HTTP_404_NOT_FOUND,
                detail="비교 결과를 찾을 수 없습니다."
            )
        
        # 변경사항 조회
        changes = db.query(PipeRevisionChange).filter(
            PipeRevisionChange.comparison_id == comparison_id
        ).all()
        
        # 재질별 길이 변화 계산
        material_impacts = {}
        
        for change in changes:
            # 재질 정보 추출
            material = None
            length_change = 0
            
            if change.change_type == "added" and change.new_material_grade:
                material = change.new_material_grade
                length_change = change.new_length_mm or 0
            elif change.change_type == "removed" and change.old_material_grade:
                material = change.old_material_grade
                length_change = -(change.old_length_mm or 0)
            elif change.change_type == "modified":
                # 재질이 같은 경우만 길이 변화 계산
                if (change.old_material_grade == change.new_material_grade and 
                    change.old_material_grade):
                    material = change.old_material_grade
                    old_length = change.old_length_mm or 0
                    new_length = change.new_length_mm or 0
                    length_change = new_length - old_length
            
            if material and length_change != 0:
                if material not in material_impacts:
                    material_impacts[material] = {
                        "material": material,
                        "total_length_change": 0,
                        "change_count": 0
                    }
                
                material_impacts[material]["total_length_change"] += length_change
                material_impacts[material]["change_count"] += 1
        
        # 결과 정리
        impact_summary = []
        for material, impact in material_impacts.items():
            length_change_m = impact["total_length_change"] / 1000  # mm to m
            impact_summary.append({
                "material": material,
                "length_change_mm": impact["total_length_change"],
                "length_change_m": round(length_change_m, 3),
                "change_count": impact["change_count"],
                "impact_type": "increase" if length_change_m > 0 else "decrease",
                "requires_additional_purchase": length_change_m > 0
            })
        
        # 전체 영향 요약
        total_additional_purchase = sum(
            impact["length_change_m"] for impact in impact_summary 
            if impact["requires_additional_purchase"]
        )
        
        return {
            "comparison_id": comparison_id,
            "job_no": comparison.job_no,
            "material_impacts": impact_summary,
            "summary": {
                "total_materials_affected": len(impact_summary),
                "materials_requiring_additional_purchase": len([
                    i for i in impact_summary if i["requires_additional_purchase"]
                ]),
                "total_additional_purchase_needed": total_additional_purchase > 0,
                "total_additional_length_m": round(total_additional_purchase, 3)
            }
        }
        
    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"Failed to get purchase impact: {e}")
        raise HTTPException(
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
            detail=f"구매 영향 분석 실패: {str(e)}"
        )
