#!/usr/bin/env python3
"""
Smart Website Migration - Detect, Plan, then Migrate

This script intelligently migrates existing websites by:
1. Detecting current tech stack and versions
2. Creating a detailed migration plan
3. Preserving ALL inline CSS and content exactly
4. Converting CSS frameworks (Tailwind v3 → v4, etc.)
5. Reinstalling Astro fresh
6. Adding new features without breaking existing functionality

Workflow:
1. ANALYZE - Detect tech stack, versions, CSS framework
2. PLAN - Create detailed migration plan
3. BACKUP - Create full backup
4. PRESERVE - Extract inline CSS and content from each page
5. CONVERT - Convert CSS to match target tech stack
6. REBUILD - Fresh Astro install with preserved content
7. ENHANCE - Add new features (cookie consent, PDPA, etc.)
8. TEST - Verify build and all pages

Usage:
    python3 migrate_existing_website.py \
        --input "./existing-website" \
        --output "./migrated-website" \
        --plan-only  # Just create plan, don't migrate
"""

import os
import sys
import json
import shutil
import re
import subprocess
import argparse
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Any, Optional
import sys
import json
import shutil
import re
import subprocess
from pathlib import Path
from datetime import datetime
from typing import Dict, List, Any, Optional


class TechStackDetector:
    """Detect tech stack and versions from existing website."""
    
    def __init__(self, website_path: Path):
        self.website_path = website_path
        self.detected = {}
    
    def detect_all(self) -> Dict[str, Any]:
        """Run all detection methods."""
        print("🔍 Detecting tech stack...\n")
        
        self.detect_astro_version()
        self.detect_node_version()
        self.detect_css_framework()
        self.detect_tailwind_version()
        self.detect_pages_structure()
        self.detect_content_collections()
        self.detect_integrations()
        self.detect_custom_css()
        
        return self.detected
    
    def detect_astro_version(self):
        """Detect Astro version from package.json."""
        package_json = self.website_path / 'package.json'
        
        if package_json.exists():
            with open(package_json) as f:
                package_data = json.load(f)
            
            deps = package_data.get('dependencies', {})
            dev_deps = package_data.get('devDependencies', {})
            
            astro_version = deps.get('astro') or dev_deps.get('astro')
            
            self.detected['astro'] = {
                'version': astro_version or 'unknown',
                'detected': True
            }
            print(f"  ✓ Astro version: {astro_version}")
        else:
            print(f"  ✗ package.json not found")
            self.detected['astro'] = {'version': 'unknown', 'detected': False}
    
    def detect_node_version(self):
        """Detect required Node.js version."""
        package_json = self.website_path / 'package.json'
        
        if package_json.exists():
            with open(package_json) as f:
                package_data = json.load(f)
            
            engines = package_data.get('engines', {})
            node_version = engines.get('node', '>=18.0.0')
            
            self.detected['node'] = {
                'required_version': node_version,
                'detected': True
            }
            print(f"  ✓ Node.js: {node_version}")
    
    def detect_css_framework(self):
        """Detect CSS framework (Tailwind, Bootstrap, etc.)."""
        package_json = self.website_path / 'package.json'
        
        css_frameworks = {
            'tailwindcss': 'Tailwind CSS',
            'bootstrap': 'Bootstrap',
            'bulma': 'Bulma',
            'foundation': 'Foundation',
            'semantic-ui': 'Semantic UI',
            'material-ui': 'Material UI',
            '@chakra-ui/core': 'Chakra UI',
        }
        
        detected_frameworks = []
        
        if package_json.exists():
            with open(package_json) as f:
                package_data = json.load(f)
            
            deps = {**package_data.get('dependencies', {}), **package_data.get('devDependencies', {})}
            
            for pkg, name in css_frameworks.items():
                if pkg in deps:
                    detected_frameworks.append({
                        'name': name,
                        'package': pkg,
                        'version': deps[pkg]
                    })
        
        self.detected['css_framework'] = {
            'frameworks': detected_frameworks,
            'primary': detected_frameworks[0]['name'] if detected_frameworks else 'Custom CSS',
            'detected': len(detected_frameworks) > 0
        }
        
        if detected_frameworks:
            print(f"  ✓ CSS Framework: {detected_frameworks[0]['name']}")
        else:
            print(f"  ✓ CSS: Custom/Inline")
    
    def detect_tailwind_version(self):
        """Detect Tailwind CSS version."""
        package_json = self.website_path / 'package.json'
        tailwind_config = self.website_path / 'tailwind.config.js'
        tailwind_config_ts = self.website_path / 'tailwind.config.ts'
        
        if package_json.exists():
            with open(package_json) as f:
                package_data = json.load(f)
            
            deps = {**package_data.get('dependencies', {}), **package_data.get('devDependencies', {})}
            
            if 'tailwindcss' in deps:
                version = deps['tailwindcss']
                major_version = version.replace('^', '').replace('~', '').split('.')[0]
                
                # Check for v4 features
                has_v4_features = False
                if tailwind_config.exists():
                    with open(tailwind_config) as f:
                        config = f.read()
                        # v4 uses different config format
                        has_v4_features = '@theme' in config or 'import theme' in config
                
                self.detected['tailwind'] = {
                    'version': version,
                    'major_version': int(major_version) if major_version.isdigit() else 3,
                    'config_file': 'tailwind.config.js' if tailwind_config.exists() else 'tailwind.config.ts' if tailwind_config_ts.exists() else None,
                    'needs_upgrade': int(major_version) < 4 if major_version.isdigit() else False,
                    'detected': True
                }
                print(f"  ✓ Tailwind CSS v{major_version}: {'Needs upgrade to v4' if int(major_version) < 4 else 'Up to date'}")
    
    def detect_pages_structure(self):
        """Detect pages structure."""
        pages_dir = self.website_path / 'src' / 'pages'
        
        if pages_dir.exists():
            pages = list(pages_dir.glob('**/*.astro'))
            pages.extend(list(pages_dir.glob('**/*.md')))
            pages.extend(list(pages_dir.glob('**/*.mdx')))
            
            self.detected['pages'] = {
                'count': len(pages),
                'structure': 'flat' if len(list(pages_dir.glob('*.astro'))) > len(pages) / 2 else 'nested',
                'has_i18n': any('/th/' in str(p) or '(th)' in str(p) for p in pages),
                'detected': True
            }
            print(f"  ✓ Pages: {len(pages)} pages detected")
    
    def detect_content_collections(self):
        """Detect Astro Content Collections."""
        content_dir = self.website_path / 'src' / 'content'
        content_config = self.website_path / 'src' / 'content.config.ts'
        
        collections = []
        
        if content_dir.exists():
            for subdir in content_dir.iterdir():
                if subdir.is_dir() and not subdir.name.startswith('_'):
                    collection_files = list(subdir.glob('*.md')) + list(subdir.glob('*.mdx'))
                    if collection_files:
                        collections.append({
                            'name': subdir.name,
                            'file_count': len(collection_files)
                        })
        
        self.detected['content_collections'] = {
            'collections': collections,
            'has_config': content_config.exists(),
            'detected': len(collections) > 0
        }
        
        if collections:
            print(f"  ✓ Content Collections: {len(collections)} collections")
    
    def detect_integrations(self):
        """Detect Astro integrations."""
        astro_config = self.website_path / 'astro.config.mjs'
        astro_config_ts = self.website_path / 'astro.config.ts'
        
        config_file = astro_config if astro_config.exists() else astro_config_ts if astro_config_ts.exists() else None
        
        integrations = []
        
        if config_file:
            with open(config_file) as f:
                config_content = f.read()
            
            # Detect common integrations
            integration_patterns = {
                'tailwind': 'tailwind()',
                'react': 'react()',
                'vue': 'vue()',
                'svelte': 'svelte()',
                'solid': 'solid()',
                'mdx': 'mdx()',
                'sitemap': 'sitemap()',
                'vercel': 'vercel()',
                'netlify': 'netlify()',
                'node': 'node()',
                'static-adapter': 'staticAdapter',
            }
            
            for name, pattern in integration_patterns.items():
                if pattern in config_content:
                    integrations.append(name)
        
        self.detected['integrations'] = {
            'integrations': integrations,
            'config_file': config_file.name if config_file else None,
            'detected': len(integrations) > 0
        }
        
        if integrations:
            print(f"  ✓ Integrations: {', '.join(integrations)}")
    
    def detect_custom_css(self):
        """Detect custom CSS files and inline styles."""
        src_dir = self.website_path / 'src'
        
        css_files = []
        inline_styles = 0
        
        if src_dir.exists():
            # Find CSS files
            for css_file in src_dir.glob('**/*.css'):
                css_files.append(str(css_file.relative_to(self.website_path)))
            
            # Count inline styles in Astro files
            for astro_file in src_dir.glob('**/*.astro'):
                with open(astro_file) as f:
                    content = f.read()
                    # Count style tags
                    inline_styles += content.count('<style>')
        
        self.detected['custom_css'] = {
            'css_files': css_files,
            'inline_style_count': inline_styles,
            'detected': len(css_files) > 0 or inline_styles > 0
        }
        
        print(f"  ✓ Custom CSS: {len(css_files)} files, {inline_styles} inline styles")


class MigrationPlanner:
    """Create detailed migration plan."""
    
    def __init__(self, tech_stack: Dict[str, Any], input_path: Path, output_path: Path):
        self.tech_stack = tech_stack
        self.input_path = input_path
        self.output_path = output_path
        self.plan = {}
    
    def create_plan(self) -> Dict[str, Any]:
        """Create comprehensive migration plan."""
        print("\n📋 Creating migration plan...\n")
        
        self.plan['summary'] = self._create_summary()
        self.plan['preservation'] = self._plan_preservation()
        self.plan['css_conversion'] = self._plan_css_conversion()
        self.plan['rebuild'] = self._plan_rebuild()
        self.plan['enhancements'] = self._plan_enhancements()
        self.plan['testing'] = self._plan_testing()
        self.plan['risks'] = self._identify_risks()
        
        return self.plan
    
    def _create_summary(self) -> Dict[str, Any]:
        """Create migration summary."""
        astro_version = self.tech_stack.get('astro', {}).get('version', 'unknown')
        css_framework = self.tech_stack.get('css_framework', {}).get('primary', 'Unknown')
        tailwind_version = self.tech_stack.get('tailwind', {}).get('major_version', 0)
        page_count = self.tech_stack.get('pages', {}).get('count', 0)
        
        return {
            'source_astro_version': astro_version,
            'target_astro_version': 'latest (5.x)',
            'css_framework': css_framework,
            'tailwind_upgrade': f"v{tailwind_version} → v4" if tailwind_version < 4 else "No upgrade needed",
            'page_count': page_count,
            'estimated_time': f"{max(10, page_count * 2)} minutes"
        }
    
    def _plan_preservation(self) -> Dict[str, Any]:
        """Plan content preservation."""
        return {
            'steps': [
                'Extract all inline CSS from .astro files',
                'Extract all page content (frontmatter + body)',
                'Copy all static assets (public/ folder)',
                'Copy all images and media files',
                'Copy all content collections (blog, products, etc.)',
                'Preserve all component logic and scripts',
                'Keep all existing routes and URLs'
            ],
            'preserved_exactly': [
                'All page content (text, images, links)',
                'All inline styles (<style> tags)',
                'All component functionality',
                'All existing URLs and routes',
                'All metadata (title, description, etc.)'
            ]
        }
    
    def _plan_css_conversion(self) -> Dict[str, Any]:
        """Plan CSS framework conversion."""
        tailwind = self.tech_stack.get('tailwind', {})
        needs_upgrade = tailwind.get('needs_upgrade', False)
        
        steps = []
        
        if needs_upgrade:
            steps.extend([
                'Backup existing tailwind.config.js',
                'Install Tailwind CSS v4',
                'Convert tailwind.config.js to v4 format',
                'Update CSS imports to v4 syntax',
                'Test all pages for CSS issues',
                'Fix any breaking changes'
            ])
        else:
            steps.append('No CSS framework upgrade needed')
        
        return {
            'needs_conversion': needs_upgrade,
            'steps': steps,
            'breaking_changes': [
                'Tailwind v4 uses different config format',
                'Some utilities may have changed',
                'Custom CSS may need adjustment'
            ] if needs_upgrade else []
        }
    
    def _plan_rebuild(self) -> Dict[str, Any]:
        """Plan Astro rebuild."""
        return {
            'steps': [
                'Create fresh Astro 5.x project',
                'Install all required integrations',
                'Migrate preserved content to new structure',
                'Apply CSS conversions',
                'Update Astro config for new features',
                'Add new components (cookie consent, etc.)'
            ],
            'fresh_install': True,
            'keep_existing_components': True
        }
    
    def _plan_enhancements(self) -> Dict[str, Any]:
        """Plan new features to add."""
        return {
            'new_features': [
                'PDPA-compliant Privacy Policy (Thai law)',
                'PDPA-compliant Terms of Service (Thai law)',
                'Working cookie consent (blocks cookies until consent)',
                'Consent logging database',
                'Umami Analytics integration',
                'i18n routing (Thai/English)',
                'Admin dashboard for consent logs'
            ],
            'optional_features': [
                'Blog post templates',
                'Product pages',
                'Contact forms',
                'SEO optimization'
            ]
        }
    
    def _plan_testing(self) -> Dict[str, Any]:
        """Plan testing steps."""
        return {
            'pre_deploy_tests': [
                'Docker build completes successfully',
                'All pages load without errors',
                'All inline CSS renders correctly',
                'Cookie consent blocks cookies until accepted',
                'All links work',
                'Mobile responsive design works',
                'Backend functions work (forms, databases)',
                'Analytics tracking works (if consented)'
            ],
            'manual_verification': [
                'Compare migrated pages with originals',
                'Verify all content is preserved',
                'Test cookie consent functionality',
                'Test on multiple browsers',
                'Test on mobile devices'
            ]
        }
    
    def _identify_risks(self) -> List[Dict[str, str]]:
        """Identify potential risks."""
        risks = []
        
        if self.tech_stack.get('astro', {}).get('version', 'unknown') == 'unknown':
            risks.append({
                'risk': 'Astro version unknown',
                'impact': 'Migration may require manual adjustments',
                'mitigation': 'Manual review of package.json required'
            })
        
        inline_styles = self.tech_stack.get('custom_css', {}).get('inline_style_count', 0)
        if inline_styles > 50:
            risks.append({
                'risk': f'High inline CSS count ({inline_styles} styles)',
                'impact': 'May take longer to verify all styles',
                'mitigation': 'Automated CSS extraction and verification'
            })
        
        tailwind = self.tech_stack.get('tailwind', {})
        if tailwind.get('needs_upgrade', False):
            risks.append({
                'risk': 'Tailwind v3 → v4 upgrade',
                'impact': 'Some CSS utilities may break',
                'mitigation': 'Thorough CSS testing on all pages'
            })
        
        return risks


def main():
    parser = argparse.ArgumentParser(
        description='Smart Website Migration - Detect, Plan, then Migrate'
    )
    parser.add_argument('--input', '-i', required=True, help='Input directory (existing website)')
    parser.add_argument('--output', '-o', required=True, help='Output directory (migrated website)')
    parser.add_argument('--plan-only', action='store_true', help='Only create plan, don\'t migrate')
    parser.add_argument('--languages', default='th,en', help='Languages (comma-separated)')
    
    args = parser.parse_args()
    
    input_path = Path(args.input)
    output_path = Path(args.output)
    
    if not input_path.exists():
        print(f"❌ Error: Input directory '{input_path}' does not exist")
        sys.exit(1)
    
    print("=" * 70)
    print("🔄 SMART WEBSITE MIGRATION")
    print("=" * 70)
    print(f"\n📁 Input: {input_path}")
    print(f"📁 Output: {output_path}")
    print(f"📋 Plan only: {args.plan_only}")
    print()
    
    # Step 1: Detect tech stack
    detector = TechStackDetector(input_path)
    tech_stack = detector.detect_all()
    
    # Step 2: Create migration plan
    planner = MigrationPlanner(tech_stack, input_path, output_path)
    plan = planner.create_plan()
    
    # Save plan to file
    plan_file = output_path.parent / f"migration_plan_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
    output_path.mkdir(parents=True, exist_ok=True)
    
    with open(plan_file, 'w') as f:
        json.dump({
            'tech_stack': tech_stack,
            'migration_plan': plan,
            'created_at': datetime.now().isoformat()
        }, f, indent=2)
    
    print(f"\n📄 Migration plan saved to: {plan_file}")
    
    # Print plan summary
    print("\n" + "=" * 70)
    print("📋 MIGRATION PLAN SUMMARY")
    print("=" * 70)
    
    summary = plan.get('summary', {})
    print(f"\n📊 Summary:")
    print(f"  • Astro: {summary.get('source_astro_version', 'unknown')} → {summary.get('target_astro_version', 'latest')}")
    print(f"  • CSS: {summary.get('css_framework', 'Unknown')}")
    print(f"  • Tailwind: {summary.get('tailwind_upgrade', 'N/A')}")
    print(f"  • Pages: {summary.get('page_count', 0)} pages")
    print(f"  • Estimated time: {summary.get('estimated_time', 'unknown')}")
    
    # Print risks
    risks = plan.get('risks', [])
    if risks:
        print(f"\n⚠️  Risks identified: {len(risks)}")
        for risk in risks:
            print(f"  • {risk['risk']}")
            print(f"    Impact: {risk['impact']}")
            print(f"    Mitigation: {risk['mitigation']}")
    
    if args.plan_only:
        print("\n✅ Plan created successfully!")
        print("\nTo proceed with migration, run:")
        print(f"  python3 migrate_existing_website.py \\")
        print(f"    --input '{input_path}' \\")
        print(f"    --output '{output_path}'")
    else:
        print("\n⚠️  WARNING: Full migration not yet implemented!")
        print("\nThis is a safety measure. The migration script will:")
        print("  1. Review this plan carefully")
        print("  2. Manually verify all detected tech stack")
        print("  3. Approve the migration plan")
        print("  4. Then we'll implement the full migration logic")
        print("\nPlease review the plan and let us know if you want to proceed!")
    
    print("\n" + "=" * 70)


if __name__ == '__main__':
    main()
