#!/usr/bin/env python3
"""
3D 객체인식 평가 시스템 메인 실행 파일
TRELLIS 모델을 통해 변환된 3D 모델의 객체 인식 정확도를 측정합니다.
"""

import argparse
import sys
import os
import logging
from pathlib import Path
from typing import Optional

# 프로젝트 루트를 Python 경로에 추가
project_root = Path(__file__).parent
sys.path.insert(0, str(project_root))

from src.evaluator import Evaluator
from src.visualizer import Visualizer
from config.evaluation_config import EVALUATION_CONFIG, validate_config


def setup_logging(level: str = 'INFO') -> None:
    """
    로깅을 설정합니다.
    
    Args:
        level (str): 로그 레벨
    """
    logging.basicConfig(
        level=getattr(logging, level.upper()),
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
        handlers=[
            logging.StreamHandler(),
            logging.FileHandler('evaluation.log')
        ]
    )


def parse_arguments() -> argparse.Namespace:
    """
    명령행 인자를 파싱합니다.
    
    Returns:
        argparse.Namespace: 파싱된 인자들
    """
    parser = argparse.ArgumentParser(
        description='3D 객체인식 평가 시스템',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
사용 예시:
  python main.py --model model.glb --reference model_image.png
  python main.py --model model.glb --reference model_image.png --output results/ --visualize
  python main.py --model model.glb --reference model_image.png --config custom_config.py
        """
    )
    
    # 필수 인자
    parser.add_argument(
        '--model', '-m',
        type=str,
        required=True,
        help='변환된 3D 모델 파일 경로 (GLB, GLTF, OBJ, PLY, STL 형식 지원)'
    )
    
    parser.add_argument(
        '--reference', '-r',
        type=str,
        required=True,
        help='참조 이미지 파일 경로 (PNG, JPG, JPEG, BMP, TIFF 형식 지원)'
    )
    
    # 선택적 인자
    parser.add_argument(
        '--output', '-o',
        type=str,
        default='results',
        help='결과 출력 디렉토리 (기본값: results)'
    )
    
    parser.add_argument(
        '--config', '-c',
        type=str,
        help='사용자 정의 설정 파일 경로'
    )
    
    parser.add_argument(
        '--visualize', '-v',
        action='store_true',
        help='결과 시각화 활성화'
    )
    
    parser.add_argument(
        '--save-report',
        action='store_true',
        help='상세 리포트 저장'
    )
    
    parser.add_argument(
        '--log-level',
        type=str,
        choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'],
        default='INFO',
        help='로그 레벨 (기본값: INFO)'
    )
    
    parser.add_argument(
        '--quiet', '-q',
        action='store_true',
        help='상세 출력 비활성화'
    )
    
    parser.add_argument(
        '--version',
        action='version',
        version='3D 객체인식 평가 시스템 v1.0.0'
    )
    
    return parser.parse_args()


def load_custom_config(config_path: str) -> dict:
    """
    사용자 정의 설정 파일을 로드합니다.
    
    Args:
        config_path (str): 설정 파일 경로
        
    Returns:
        dict: 로드된 설정
    """
    try:
        if config_path.endswith('.py'):
            # Python 파일인 경우
            import importlib.util
            spec = importlib.util.spec_from_file_location("custom_config", config_path)
            custom_config = importlib.util.module_from_spec(spec)
            spec.loader.exec_module(custom_config)
            return custom_config.EVALUATION_CONFIG
        elif config_path.endswith('.json'):
            # JSON 파일인 경우
            import json
            with open(config_path, 'r', encoding='utf-8') as f:
                return json.load(f)
        else:
            raise ValueError("지원하지 않는 설정 파일 형식입니다. (.py 또는 .json 파일을 사용하세요)")
    except Exception as e:
        logging.error(f"설정 파일 로드 실패: {e}")
        return EVALUATION_CONFIG


def validate_input_files(model_path: str, reference_path: str) -> bool:
    """
    입력 파일들의 유효성을 검증합니다.
    
    Args:
        model_path (str): 3D 모델 파일 경로
        reference_path (str): 참조 이미지 파일 경로
        
    Returns:
        bool: 파일 유효성
    """
    # 파일 존재 확인
    if not os.path.exists(model_path):
        print(f"오류: 3D 모델 파일이 존재하지 않습니다: {model_path}")
        return False
    
    if not os.path.exists(reference_path):
        print(f"오류: 참조 이미지 파일이 존재하지 않습니다: {reference_path}")
        return False
    
    # 파일 확장자 확인
    model_ext = os.path.splitext(model_path)[1].lower()
    reference_ext = os.path.splitext(reference_path)[1].lower()
    
    supported_3d_formats = ['.glb', '.gltf', '.obj', '.ply', '.stl']
    supported_image_formats = ['.png', '.jpg', '.jpeg', '.bmp', '.tiff']
    
    if model_ext not in supported_3d_formats:
        print(f"오류: 지원하지 않는 3D 파일 형식입니다: {model_ext}")
        print(f"지원 형식: {', '.join(supported_3d_formats)}")
        return False
    
    if reference_ext not in supported_image_formats:
        print(f"오류: 지원하지 않는 이미지 파일 형식입니다: {reference_ext}")
        print(f"지원 형식: {', '.join(supported_image_formats)}")
        return False
    
    return True


def print_evaluation_summary(results: dict) -> None:
    """
    평가 결과 요약을 출력합니다.
    
    Args:
        results (dict): 평가 결과
    """
    print("\n" + "="*50)
    print("=== TRELLIS 모델 평가 결과 ===")
    print("="*50)
    print(f"종합 점수: {results['comprehensive_score']:.1f}점")
    print(f"성능 등급: {results['grade']}등급")
    print()
    
    print("=== 개별 지표 점수 ===")
    for metric_name, details in results['score_details'].items():
        print(f"{metric_name}: {details['normalized_score']:.1f}점")
    print()
    
    print("=== 원본 지표 값 ===")
    for metric_name, value in results['metrics'].items():
        print(f"{metric_name}: {value:.4f}")
    print()
    
    print(f"평가 시간: {results['evaluation_timestamp']}")
    print("="*50)


def main():
    """메인 함수"""
    try:
        # 명령행 인자 파싱
        args = parse_arguments()
        
        # 로깅 설정
        setup_logging(args.log_level)
        logger = logging.getLogger(__name__)
        
        if not args.quiet:
            print("3D 객체인식 평가 시스템 v1.0.0")
            print("="*50)
        
        # 입력 파일 검증
        if not validate_input_files(args.model, args.reference):
            sys.exit(1)
        
        # 설정 로드
        if args.config:
            logger.info(f"사용자 정의 설정 로드: {args.config}")
            config = load_custom_config(args.config)
        else:
            config = EVALUATION_CONFIG
        
        # 설정 검증
        if not validate_config(config):
            logger.warning("설정 검증에서 경고가 발생했습니다.")
        
        # 출력 디렉토리 설정 업데이트
        config['file_paths']['output_dir'] = args.output
        config['file_paths']['images_dir'] = os.path.join(args.output, 'images')
        config['file_paths']['reports_dir'] = os.path.join(args.output, 'reports')
        config['file_paths']['temp_dir'] = os.path.join(args.output, 'temp')
        
        # 출력 디렉토리 생성
        os.makedirs(args.output, exist_ok=True)
        os.makedirs(config['file_paths']['images_dir'], exist_ok=True)
        os.makedirs(config['file_paths']['reports_dir'], exist_ok=True)
        os.makedirs(config['file_paths']['temp_dir'], exist_ok=True)
        
        # 평가 엔진 초기화
        logger.info("평가 엔진 초기화 중...")
        evaluator = Evaluator(config)
        
        # 평가 실행
        logger.info("모델 평가 시작...")
        results = evaluator.evaluate_model(args.model, args.reference)
        
        # 결과 출력
        if not args.quiet:
            print_evaluation_summary(results)
        
        # 시각화
        if args.visualize:
            logger.info("결과 시각화 중...")
            visualizer = Visualizer(args.output)
            
            # 지표 비교 차트 생성
            visualizer.plot_metrics_comparison(results)
            
            # 성능 대시보드 생성
            dashboard_path = visualizer.create_performance_dashboard(results)
            print(f"성능 대시보드: {dashboard_path}")
        
        # 리포트 저장
        if args.save_report:
            logger.info("상세 리포트 생성 중...")
            visualizer = Visualizer(args.output)
            report_path = visualizer.generate_html_report(results)
            print(f"상세 리포트: {report_path}")
        
        # JSON 결과 저장
        import json
        results_file = os.path.join(args.output, 'evaluation_results.json')
        with open(results_file, 'w', encoding='utf-8') as f:
            json.dump(results, f, indent=2, ensure_ascii=False)
        
        if not args.quiet:
            print(f"\n결과가 저장되었습니다: {results_file}")
            print("평가가 성공적으로 완료되었습니다!")
        
        logger.info("평가 완료")
        
    except KeyboardInterrupt:
        print("\n사용자에 의해 평가가 중단되었습니다.")
        sys.exit(1)
    except Exception as e:
        logger.error(f"평가 중 오류 발생: {e}")
        if not args.quiet:
            print(f"\n오류: {e}")
        sys.exit(1)


if __name__ == "__main__":
    main()
