"""
리비전 상태 관리 서비스
리비전 진행 상태, 히스토리, 확정 등 관리
"""

from sqlalchemy.orm import Session
from sqlalchemy import text, desc
from typing import List, Dict, Any, Optional
from datetime import datetime

from ..models import File, RevisionComparison, RevisionChangeLog
from ..utils.logger import get_logger
from .database_service import DatabaseService

logger = get_logger(__name__)


class RevisionStatusService:
    """리비전 상태 관리 서비스"""
    
    def __init__(self, db: Session):
        self.db = db
        self.db_service = DatabaseService(db)
    
    def get_revision_status(self, job_no: str, file_id: int) -> Dict[str, Any]:
        """
        리비전 상태 조회
        
        Args:
            job_no: 작업 번호
            file_id: 파일 ID
            
        Returns:
            리비전 상태 정보
        """
        
        # 파일 정보 조회
        current_file = self._get_file_info(file_id)
        if not current_file:
            return {"error": "파일을 찾을 수 없습니다."}
        
        # 같은 작업의 모든 파일 조회
        all_files = self._get_job_files(job_no)
        
        # 리비전 히스토리 구성
        revision_history = self._build_revision_history(all_files, file_id)
        
        # 현재 리비전의 처리 상태
        processing_status = self._get_processing_status(file_id)
        
        return {
            "job_no": job_no,
            "current_file": current_file,
            "revision_history": revision_history,
            "processing_status": processing_status,
            "is_latest": revision_history.get("is_latest", False),
            "can_upload_new_revision": revision_history.get("can_upload_new", True),
            "status_summary": self._generate_status_summary(processing_status)
        }
    
    def get_revision_history(self, job_no: str) -> List[Dict[str, Any]]:
        """작업의 전체 리비전 히스토리 조회"""
        
        files = self._get_job_files(job_no)
        
        history = []
        for i, file_info in enumerate(files):
            # 이전 파일과의 비교 정보
            comparison_info = None
            if i > 0:
                prev_file = files[i-1]
                comparison_info = self._get_comparison_summary(file_info['id'], prev_file['id'])
            
            history.append({
                "file_id": file_info['id'],
                "revision": file_info['revision'],
                "filename": file_info['original_filename'],
                "upload_date": file_info['upload_date'],
                "uploaded_by": file_info['uploaded_by'],
                "file_size": file_info['file_size'],
                "material_count": self._get_material_count(file_info['id']),
                "comparison_with_previous": comparison_info,
                "is_latest": i == 0,  # 최신순 정렬이므로 첫 번째가 최신
                "processing_status": self._get_processing_status(file_info['id'])
            })
        
        return history
    
    def create_revision_comparison_record(
        self,
        job_no: str,
        current_file_id: int,
        previous_file_id: int,
        comparison_result: Dict[str, Any],
        created_by: str
    ) -> int:
        """리비전 비교 기록 생성"""
        
        try:
            comparison_record = RevisionComparison(
                job_no=job_no,
                current_file_id=current_file_id,
                previous_file_id=previous_file_id,
                comparison_result=comparison_result,
                summary_stats=comparison_result.get("summary", {}),
                created_by=created_by,
                is_applied=False
            )
            
            self.db.add(comparison_record)
            self.db.commit()
            self.db.refresh(comparison_record)
            
            logger.info(f"Created revision comparison record: {comparison_record.id}")
            return comparison_record.id
            
        except Exception as e:
            self.db.rollback()
            logger.error(f"Failed to create revision comparison record: {e}")
            raise
    
    def apply_revision_comparison(
        self,
        comparison_id: int,
        applied_by: str
    ) -> Dict[str, Any]:
        """리비전 비교 결과 적용"""
        
        try:
            # 비교 기록 조회
            comparison = self.db.query(RevisionComparison).filter(
                RevisionComparison.id == comparison_id
            ).first()
            
            if not comparison:
                return {"success": False, "error": "비교 기록을 찾을 수 없습니다."}
            
            if comparison.is_applied:
                return {"success": False, "error": "이미 적용된 비교 결과입니다."}
            
            # 적용 처리
            comparison.is_applied = True
            comparison.applied_at = datetime.utcnow()
            comparison.applied_by = applied_by
            
            # 변경 로그 생성
            self._create_change_logs(comparison)
            
            self.db.commit()
            
            logger.info(f"Applied revision comparison: {comparison_id}")
            
            return {
                "success": True,
                "comparison_id": comparison_id,
                "applied_at": comparison.applied_at.isoformat(),
                "applied_by": applied_by
            }
            
        except Exception as e:
            self.db.rollback()
            logger.error(f"Failed to apply revision comparison: {e}")
            return {"success": False, "error": str(e)}
    
    def get_pending_revisions(self, job_no: Optional[str] = None) -> List[Dict[str, Any]]:
        """대기 중인 리비전 목록 조회"""
        
        query = """
            SELECT 
                rc.id, rc.job_no, rc.current_file_id, rc.previous_file_id,
                rc.comparison_date, rc.created_by, rc.summary_stats,
                cf.original_filename as current_filename,
                cf.revision as current_revision,
                pf.original_filename as previous_filename,
                pf.revision as previous_revision
            FROM revision_comparisons rc
            JOIN files cf ON rc.current_file_id = cf.id
            LEFT JOIN files pf ON rc.previous_file_id = pf.id
            WHERE rc.is_applied = false
        """
        
        params = {}
        if job_no:
            query += " AND rc.job_no = :job_no"
            params["job_no"] = job_no
        
        query += " ORDER BY rc.comparison_date DESC"
        
        result = self.db_service.execute_query(query, params)
        
        pending_revisions = []
        for row in result.fetchall():
            row_dict = dict(row._mapping)
            pending_revisions.append({
                "comparison_id": row_dict['id'],
                "job_no": row_dict['job_no'],
                "current_file": {
                    "id": row_dict['current_file_id'],
                    "filename": row_dict['current_filename'],
                    "revision": row_dict['current_revision']
                },
                "previous_file": {
                    "id": row_dict['previous_file_id'],
                    "filename": row_dict['previous_filename'],
                    "revision": row_dict['previous_revision']
                } if row_dict['previous_file_id'] else None,
                "comparison_date": row_dict['comparison_date'],
                "created_by": row_dict['created_by'],
                "summary_stats": row_dict['summary_stats']
            })
        
        return pending_revisions
    
    def _get_file_info(self, file_id: int) -> Optional[Dict[str, Any]]:
        """파일 정보 조회"""
        
        query = """
            SELECT 
                id, filename, original_filename, file_path, job_no, revision,
                bom_name, description, file_size, parsed_count,
                upload_date, uploaded_by, is_active
            FROM files
            WHERE id = :file_id
        """
        
        result = self.db_service.execute_query(query, {"file_id": file_id})
        row = result.fetchone()
        
        return dict(row._mapping) if row else None
    
    def _get_job_files(self, job_no: str) -> List[Dict[str, Any]]:
        """작업의 모든 파일 조회 (최신순)"""
        
        query = """
            SELECT 
                id, filename, original_filename, file_path, job_no, revision,
                bom_name, description, file_size, parsed_count,
                upload_date, uploaded_by, is_active
            FROM files
            WHERE job_no = :job_no AND is_active = true
            ORDER BY upload_date DESC, id DESC
        """
        
        result = self.db_service.execute_query(query, {"job_no": job_no})
        
        return [dict(row._mapping) for row in result.fetchall()]
    
    def _build_revision_history(self, all_files: List[Dict], current_file_id: int) -> Dict[str, Any]:
        """리비전 히스토리 구성"""
        
        current_index = None
        for i, file_info in enumerate(all_files):
            if file_info['id'] == current_file_id:
                current_index = i
                break
        
        if current_index is None:
            return {"error": "현재 파일을 찾을 수 없습니다."}
        
        return {
            "total_revisions": len(all_files),
            "current_position": current_index + 1,  # 1-based
            "is_latest": current_index == 0,
            "is_first": current_index == len(all_files) - 1,
            "can_upload_new": current_index == 0,  # 최신 리비전에서만 새 리비전 업로드 가능
            "previous_file_id": all_files[current_index + 1]['id'] if current_index < len(all_files) - 1 else None,
            "next_file_id": all_files[current_index - 1]['id'] if current_index > 0 else None
        }
    
    def _get_processing_status(self, file_id: int) -> Dict[str, Any]:
        """파일의 처리 상태 조회"""
        
        # 자재별 처리 상태 통계
        query = """
            SELECT 
                classified_category,
                COUNT(*) as total_count,
                SUM(CASE WHEN purchase_confirmed = true THEN 1 ELSE 0 END) as purchased_count,
                SUM(CASE WHEN revision_status IS NOT NULL THEN 1 ELSE 0 END) as processed_count,
                COUNT(DISTINCT COALESCE(revision_status, 'pending')) as status_types
            FROM materials
            WHERE file_id = :file_id AND is_active = true AND classified_category != 'PIPE'
            GROUP BY classified_category
        """
        
        result = self.db_service.execute_query(query, {"file_id": file_id})
        
        category_status = {}
        total_materials = 0
        total_purchased = 0
        total_processed = 0
        
        for row in result.fetchall():
            row_dict = dict(row._mapping)
            category = row_dict['classified_category']
            
            category_status[category] = {
                "total": row_dict['total_count'],
                "purchased": row_dict['purchased_count'],
                "processed": row_dict['processed_count'],
                "pending": row_dict['total_count'] - row_dict['processed_count']
            }
            
            total_materials += row_dict['total_count']
            total_purchased += row_dict['purchased_count']
            total_processed += row_dict['processed_count']
        
        return {
            "file_id": file_id,
            "total_materials": total_materials,
            "total_purchased": total_purchased,
            "total_processed": total_processed,
            "pending_processing": total_materials - total_processed,
            "category_breakdown": category_status,
            "completion_percentage": (total_processed / total_materials * 100) if total_materials > 0 else 0
        }
    
    def _get_comparison_summary(self, current_file_id: int, previous_file_id: int) -> Optional[Dict[str, Any]]:
        """비교 요약 정보 조회"""
        
        query = """
            SELECT summary_stats, comparison_date, is_applied
            FROM revision_comparisons
            WHERE current_file_id = :current_file_id AND previous_file_id = :previous_file_id
            ORDER BY comparison_date DESC
            LIMIT 1
        """
        
        result = self.db_service.execute_query(query, {
            "current_file_id": current_file_id,
            "previous_file_id": previous_file_id
        })
        
        row = result.fetchone()
        if row:
            row_dict = dict(row._mapping)
            return {
                "summary_stats": row_dict['summary_stats'],
                "comparison_date": row_dict['comparison_date'],
                "is_applied": row_dict['is_applied']
            }
        
        return None
    
    def _get_material_count(self, file_id: int) -> int:
        """파일의 자재 개수 조회"""
        
        query = """
            SELECT COUNT(*) as count
            FROM materials
            WHERE file_id = :file_id AND is_active = true AND classified_category != 'PIPE'
        """
        
        result = self.db_service.execute_query(query, {"file_id": file_id})
        row = result.fetchone()
        
        return row.count if row else 0
    
    def _create_change_logs(self, comparison: RevisionComparison):
        """변경 로그 생성"""
        
        try:
            changes = comparison.comparison_result.get("changes", {})
            
            # 각 변경사항에 대해 로그 생성
            for change_type, change_list in changes.items():
                for change_item in change_list:
                    change_log = RevisionChangeLog(
                        comparison_id=comparison.id,
                        material_id=change_item.get("material", {}).get("id"),
                        change_type=change_type,
                        previous_data=change_item.get("previous"),
                        current_data=change_item.get("current") or change_item.get("material"),
                        action_taken=change_item.get("action", change_type),
                        notes=change_item.get("reason", "")
                    )
                    
                    self.db.add(change_log)
            
            logger.info(f"Created change logs for comparison {comparison.id}")
            
        except Exception as e:
            logger.error(f"Failed to create change logs: {e}")
            raise
    
    def _generate_status_summary(self, processing_status: Dict[str, Any]) -> Dict[str, Any]:
        """상태 요약 생성"""
        
        total = processing_status.get("total_materials", 0)
        processed = processing_status.get("total_processed", 0)
        purchased = processing_status.get("total_purchased", 0)
        
        if total == 0:
            return {"status": "empty", "message": "자료가 없습니다."}
        
        completion_rate = processed / total
        
        if completion_rate >= 1.0:
            status = "completed"
            message = "모든 자재 처리 완료"
        elif completion_rate >= 0.8:
            status = "nearly_complete"
            message = f"처리 진행 중 ({processed}/{total})"
        elif completion_rate >= 0.5:
            status = "in_progress"
            message = f"처리 진행 중 ({processed}/{total})"
        else:
            status = "started"
            message = f"처리 시작됨 ({processed}/{total})"
        
        return {
            "status": status,
            "message": message,
            "completion_rate": completion_rate,
            "stats": {
                "total": total,
                "processed": processed,
                "purchased": purchased,
                "pending": total - processed
            }
        }
