#!/usr/bin/env python3

import os
import re
from pathlib import Path
from typing import Set, Dict, List, Tuple
import json

class DartFileAnalyzer:
    def __init__(self, project_root: str):
        self.project_root = Path(project_root)
        self.lib_path = self.project_root / "lib"
        self.all_files: Set[Path] = set()
        self.used_files: Set[Path] = set()
        self.import_graph: Dict[Path, Set[Path]] = {}
        
        # 진입점들
        self.entry_points = [
            self.lib_path / "main.dart",
            self.lib_path / "injection_container.dart",
            self.lib_path / "screens/common/app_layout.dart"
        ]
    
    def find_all_dart_files(self) -> None:
        """모든 .dart 파일을 찾기 (생성 파일 제외)"""
        for file_path in self.lib_path.rglob("*.dart"):
            if not (file_path.name.endswith(".g.dart") or file_path.name.endswith(".freezed.dart")):
                self.all_files.add(file_path)
                self.import_graph[file_path] = set()
    
    def extract_imports(self, file_path: Path) -> Set[Path]:
        """파일에서 import 문을 추출하고 실제 파일 경로로 변환"""
        imports = set()
        
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
                
            # import 패턴 매칭
            import_patterns = [
                r"import\s+['\"]package:superport/(.+?)['\"]",
                r"import\s+['\"](.+?\.dart)['\"]"
            ]
            
            for pattern in import_patterns:
                matches = re.findall(pattern, content)
                for match in matches:
                    if match.startswith('package:superport/'):
                        # package:superport/ import
                        relative_path = match.replace('package:superport/', '')
                        imported_file = self.lib_path / relative_path
                    else:
                        # 상대 경로 import
                        if match.startswith('../') or match.startswith('./'):
                            imported_file = file_path.parent / match
                            imported_file = imported_file.resolve()
                        else:
                            imported_file = file_path.parent / match
                    
                    if imported_file.exists() and imported_file.suffix == '.dart':
                        imports.add(imported_file)
                        
        except Exception as e:
            print(f"Warning: Could not read {file_path}: {e}")
            
        return imports
    
    def build_import_graph(self) -> None:
        """모든 파일의 import 관계를 분석"""
        print("Building import graph...")
        for file_path in self.all_files:
            self.import_graph[file_path] = self.extract_imports(file_path)
    
    def trace_used_files(self, start_file: Path, visited: Set[Path] = None) -> None:
        """진입점에서 시작해서 사용되는 모든 파일을 추적"""
        if visited is None:
            visited = set()
            
        if start_file in visited or start_file not in self.all_files:
            return
            
        visited.add(start_file)
        self.used_files.add(start_file)
        
        # 이 파일에서 import하는 모든 파일들을 재귀적으로 추적
        for imported_file in self.import_graph.get(start_file, set()):
            self.trace_used_files(imported_file, visited)
    
    def find_unused_files(self) -> Set[Path]:
        """사용되지 않는 파일들 찾기"""
        print("Tracing used files from entry points...")
        
        # 각 진입점에서 시작해서 사용되는 파일들을 추적
        for entry_point in self.entry_points:
            if entry_point.exists():
                print(f"Tracing from {entry_point.relative_to(self.project_root)}")
                self.trace_used_files(entry_point)
            else:
                print(f"Warning: Entry point {entry_point} does not exist")
        
        # test 파일들도 별도 진입점으로 처리 (필요시)
        test_files = list(self.project_root.glob("test/**/*.dart"))
        for test_file in test_files:
            if test_file.suffix == '.dart' and not (test_file.name.endswith('.g.dart') or test_file.name.endswith('.freezed.dart')):
                print(f"Tracing from test file: {test_file.relative_to(self.project_root)}")
                self.trace_used_files(test_file)
        
        unused = self.all_files - self.used_files
        return unused
    
    def categorize_unused_files(self, unused_files: Set[Path]) -> Dict[str, List[Path]]:
        """사용되지 않는 파일들을 카테고리별로 분류"""
        categories = {
            'generated_files': [],
            'models': [],
            'screens': [],
            'services': [],
            'repositories': [],
            'controllers': [],
            'widgets': [],
            'utils': [],
            'others': []
        }
        
        for file_path in unused_files:
            relative_path = file_path.relative_to(self.lib_path)
            path_str = str(relative_path)
            
            if file_path.name.endswith('.g.dart') or file_path.name.endswith('.freezed.dart'):
                categories['generated_files'].append(file_path)
            elif 'models/' in path_str:
                categories['models'].append(file_path)
            elif 'screens/' in path_str:
                categories['screens'].append(file_path)
            elif 'services/' in path_str:
                categories['services'].append(file_path)
            elif 'repositories/' in path_str:
                categories['repositories'].append(file_path)
            elif 'controller' in path_str:
                categories['controllers'].append(file_path)
            elif 'widgets/' in path_str:
                categories['widgets'].append(file_path)
            elif 'utils/' in path_str:
                categories['utils'].append(file_path)
            else:
                categories['others'].append(file_path)
        
        return categories
    
    def check_safety_for_deletion(self, file_path: Path) -> Tuple[bool, str]:
        """파일 삭제의 안전성 검사"""
        relative_path = file_path.relative_to(self.lib_path)
        path_str = str(relative_path)
        
        # 안전하게 삭제 가능한 조건들
        if file_path.name.endswith('.g.dart') or file_path.name.endswith('.freezed.dart'):
            return True, "자동 생성 파일 - 소스 파일 삭제 후 재생성 가능"
        
        # 위험할 수 있는 파일들
        critical_keywords = ['main.dart', 'injection', 'app_layout', 'core/', 'constants/']
        if any(keyword in path_str for keyword in critical_keywords):
            return False, "핵심 시스템 파일 - 삭제 전 추가 검토 필요"
        
        # pubspec.yaml에서 참조되는지 확인 필요
        if 'assets/' in path_str or 'fonts/' in path_str:
            return False, "에셋 파일 - pubspec.yaml 참조 확인 필요"
        
        return True, "안전하게 삭제 가능"
    
    def generate_report(self) -> None:
        """분석 결과 보고서 생성"""
        print("\n" + "="*80)
        print("FLUTTER 프로젝트 사용되지 않는 파일 분석 보고서")
        print("="*80)
        
        unused_files = self.find_unused_files()
        categories = self.categorize_unused_files(unused_files)
        
        print(f"\n📊 총 분석 파일: {len(self.all_files)}개")
        print(f"✅ 사용 중인 파일: {len(self.used_files)}개")
        print(f"❌ 사용되지 않는 파일: {len(unused_files)}개")
        print(f"📈 사용률: {len(self.used_files)/len(self.all_files)*100:.1f}%")
        
        # 진입점 정보
        print(f"\n🚀 분석 진입점:")
        for entry_point in self.entry_points:
            status = "✅" if entry_point.exists() else "❌"
            print(f"  {status} {entry_point.relative_to(self.project_root)}")
        
        # 카테고리별 미사용 파일
        print(f"\n📂 카테고리별 사용되지 않는 파일:")
        total_safe_to_delete = 0
        total_need_review = 0
        
        for category, files in categories.items():
            if not files:
                continue
                
            print(f"\n📁 {category.upper()} ({len(files)}개):")
            
            safe_count = 0
            review_count = 0
            
            for file_path in sorted(files):
                relative_path = file_path.relative_to(self.lib_path)
                is_safe, reason = self.check_safety_for_deletion(file_path)
                
                if is_safe:
                    safe_count += 1
                    print(f"  ✅ lib/{relative_path}")
                else:
                    review_count += 1
                    print(f"  ⚠️  lib/{relative_path} - {reason}")
            
            print(f"     안전 삭제: {safe_count}개, 검토 필요: {review_count}개")
            total_safe_to_delete += safe_count
            total_need_review += review_count
        
        # 삭제 권장사항
        print(f"\n🎯 삭제 권장사항:")
        print(f"  ✅ 즉시 안전 삭제 가능: {total_safe_to_delete}개")
        print(f"  ⚠️  추가 검토 후 삭제: {total_need_review}개")
        
        # Git status와 비교
        print(f"\n📋 Git Status와 비교 분석:")
        try:
            import subprocess
            result = subprocess.run(['git', 'status', '--porcelain'], 
                                  cwd=self.project_root, 
                                  capture_output=True, 
                                  text=True)
            git_status = result.stdout
            
            deleted_files = []
            for line in git_status.split('\n'):
                if line.startswith('D ') and line.endswith('.dart'):
                    deleted_files.append(line[3:])  # Remove 'D ' prefix
            
            if deleted_files:
                print(f"  🗑️  Git에서 이미 삭제된 파일: {len(deleted_files)}개")
                for deleted_file in deleted_files[:10]:  # Show first 10
                    print(f"     - {deleted_file}")
                if len(deleted_files) > 10:
                    print(f"     ... 및 {len(deleted_files) - 10}개 더")
            else:
                print(f"  ✅ Git에서 삭제된 dart 파일 없음")
                
        except Exception as e:
            print(f"  ❌ Git status 확인 실패: {e}")
        
        # 중요한 패턴 분석
        print(f"\n🔍 중요 패턴 분석:")
        
        # .g.dart / .freezed.dart 파일들의 소스 파일 존재 여부
        generated_files = categories.get('generated_files', [])
        if generated_files:
            orphaned_generated = []
            for gen_file in generated_files:
                if gen_file.name.endswith('.g.dart'):
                    source_file = gen_file.with_suffix('').with_suffix('.dart')
                elif gen_file.name.endswith('.freezed.dart'):
                    source_file = gen_file.parent / gen_file.name.replace('.freezed.dart', '.dart')
                else:
                    continue
                
                if source_file not in self.all_files and not source_file.exists():
                    orphaned_generated.append(gen_file)
            
            if orphaned_generated:
                print(f"  ⚠️  소스 파일이 없는 생성 파일: {len(orphaned_generated)}개")
                for orphaned in orphaned_generated[:5]:
                    print(f"     - lib/{orphaned.relative_to(self.lib_path)}")
            else:
                print(f"  ✅ 모든 생성 파일의 소스 파일 존재함")
        
        print(f"\n💡 권장사항:")
        print(f"  1. 자동 생성 파일들을 먼저 정리하세요")
        print(f"  2. 테스트 파일에서만 사용되는 파일들을 확인하세요")
        print(f"  3. 삭제 전에 git grep으로 문자열 참조 확인을 권장합니다")
        print(f"  4. 백업을 만든 후 단계적으로 삭제하세요")
        
        print("\n" + "="*80)

def main():
    project_root = "/Users/maximilian.j.sul/Documents/flutter/superport"
    analyzer = DartFileAnalyzer(project_root)
    
    print("🔍 Flutter 프로젝트 사용되지 않는 파일 분석 시작...")
    print(f"📂 프로젝트 경로: {project_root}")
    
    analyzer.find_all_dart_files()
    print(f"📄 발견된 총 Dart 파일: {len(analyzer.all_files)}개")
    
    analyzer.build_import_graph()
    analyzer.generate_report()

if __name__ == "__main__":
    main()