"""
리비전 비교 전용 서비스
두 리비전 간의 자재 비교 및 차이점 분석
"""

from sqlalchemy.orm import Session
from sqlalchemy import text
from typing import List, Dict, Any, Optional, Tuple
from decimal import Decimal
import hashlib
from datetime import datetime

from ..models import Material, File
from ..utils.logger import get_logger
from .database_service import DatabaseService

logger = get_logger(__name__)


class RevisionComparisonService:
    """리비전 비교 전용 서비스"""
    
    def __init__(self, db: Session):
        self.db = db
        self.db_service = DatabaseService(db)
    
    def compare_revisions(
        self,
        current_file_id: int,
        previous_file_id: int,
        category_filter: Optional[str] = None
    ) -> Dict[str, Any]:
        """
        두 리비전 간 자재 비교
        
        Args:
            current_file_id: 현재 리비전 파일 ID
            previous_file_id: 이전 리비전 파일 ID  
            category_filter: 특정 카테고리만 비교 (선택사항)
            
        Returns:
            비교 결과 딕셔너리
        """
        
        # 이전/현재 자재 조회
        previous_materials = self._get_materials_for_comparison(previous_file_id, category_filter)
        current_materials = self._get_materials_for_comparison(current_file_id, category_filter)
        
        # 비교 수행
        comparison_result = {
            "comparison_date": datetime.now().isoformat(),
            "current_file_id": current_file_id,
            "previous_file_id": previous_file_id,
            "category_filter": category_filter,
            "summary": {
                "previous_count": len(previous_materials),
                "current_count": len(current_materials),
                "unchanged": 0,
                "modified": 0,
                "added": 0,
                "removed": 0
            },
            "changes": {
                "unchanged": [],
                "modified": [],
                "added": [],
                "removed": []
            }
        }
        
        # 이전 자재 기준으로 비교
        for key, prev_material in previous_materials.items():
            if key in current_materials:
                curr_material = current_materials[key]
                
                # 자재 변경 여부 확인
                if self._is_material_changed(prev_material, curr_material):
                    comparison_result["changes"]["modified"].append({
                        "key": key,
                        "previous": prev_material,
                        "current": curr_material,
                        "changes": self._get_material_changes(prev_material, curr_material)
                    })
                    comparison_result["summary"]["modified"] += 1
                else:
                    comparison_result["changes"]["unchanged"].append({
                        "key": key,
                        "material": curr_material
                    })
                    comparison_result["summary"]["unchanged"] += 1
            else:
                # 제거된 자재
                comparison_result["changes"]["removed"].append({
                    "key": key,
                    "material": prev_material
                })
                comparison_result["summary"]["removed"] += 1
        
        # 신규 자재
        for key, curr_material in current_materials.items():
            if key not in previous_materials:
                comparison_result["changes"]["added"].append({
                    "key": key,
                    "material": curr_material
                })
                comparison_result["summary"]["added"] += 1
        
        return comparison_result
    
    def get_category_comparison(
        self,
        current_file_id: int,
        previous_file_id: int,
        category: str
    ) -> Dict[str, Any]:
        """특정 카테고리의 리비전 비교"""
        
        return self.compare_revisions(current_file_id, previous_file_id, category)
    
    # PIPE 관련 메서드는 별도 처리 예정
    
    def _get_materials_for_comparison(
        self,
        file_id: int,
        category_filter: Optional[str] = None
    ) -> Dict[str, Dict]:
        """비교용 자재 데이터 조회"""
        
        query = """
            SELECT 
                m.id, m.original_description, m.classified_category,
                m.material_grade, m.schedule, m.size_spec, m.main_nom, m.red_nom,
                m.quantity, m.unit, m.length, m.drawing_name, m.line_no,
                m.purchase_confirmed, m.confirmed_quantity, m.purchase_status,
                m.material_hash, m.revision_status, m.brand, m.user_requirement,
                m.line_number, m.is_active,
                -- 비교 키 생성 (PIPE 제외)
                COALESCE(m.material_hash, 
                        CONCAT(m.original_description, '|', 
                               COALESCE(m.material_grade, ''), '|',
                               COALESCE(m.size_spec, ''))) as comparison_key
            FROM materials m
            WHERE m.file_id = :file_id AND m.is_active = true
        """
        
        params = {"file_id": file_id}
        
        if category_filter:
            query += " AND m.classified_category = :category"
            params["category"] = category_filter
        
        # PIPE 카테고리는 제외
        query += " AND m.classified_category != 'PIPE'"
        
        query += " ORDER BY m.line_number"
        
        result = self.db_service.execute_query(query, params)
        materials = {}
        
        for row in result.fetchall():
            row_dict = dict(row._mapping)
            comparison_key = row_dict['comparison_key']
            
            # PIPE 제외한 일반 자재 처리
            materials[comparison_key] = row_dict
        
        return materials
    
    def _is_material_changed(self, prev_material: Dict, curr_material: Dict) -> bool:
        """자재 변경 여부 확인"""
        
        # 주요 필드 비교
        compare_fields = ['quantity', 'material_grade', 'schedule', 'size_spec', 
                         'main_nom', 'red_nom', 'unit', 'length']
        
        for field in compare_fields:
            prev_val = prev_material.get(field)
            curr_val = curr_material.get(field)
            
            # 수치 필드는 부동소수점 오차 고려
            if field in ['quantity', 'length']:
                if prev_val is not None and curr_val is not None:
                    if abs(float(prev_val) - float(curr_val)) > 0.001:
                        return True
                elif prev_val != curr_val:
                    return True
            else:
                if prev_val != curr_val:
                    return True
        
        return False
    
    def _get_material_changes(self, prev_material: Dict, curr_material: Dict) -> Dict[str, Any]:
        """자재 변경 내용 상세 분석"""
        
        changes = {}
        compare_fields = ['quantity', 'material_grade', 'schedule', 'size_spec', 
                         'main_nom', 'red_nom', 'unit', 'length']
        
        for field in compare_fields:
            prev_val = prev_material.get(field)
            curr_val = curr_material.get(field)
            
            if field in ['quantity', 'length']:
                if prev_val is not None and curr_val is not None:
                    if abs(float(prev_val) - float(curr_val)) > 0.001:
                        changes[field] = {
                            "previous": float(prev_val),
                            "current": float(curr_val),
                            "change": float(curr_val) - float(prev_val)
                        }
                elif prev_val != curr_val:
                    changes[field] = {
                        "previous": prev_val,
                        "current": curr_val
                    }
            else:
                if prev_val != curr_val:
                    changes[field] = {
                        "previous": prev_val,
                        "current": curr_val
                    }
        
        return changes
