#!/usr/bin/env python3
"""
Hotel MCP - Pre-Publish Validation

Comprehensive validation suite to ensure the package is ready for NPM publication.
Validates code quality, tests, documentation, and distribution readiness.
"""

import json
import os
import subprocess
import sys
from pathlib import Path
from typing import Dict, List, Tuple


def run_command(cmd: str, timeout: int = 60) -> Tuple[bool, str, str]:
    """Run a command and return success, stdout, stderr."""
    try:
        result = subprocess.run(
            cmd, shell=True, capture_output=True, text=True, timeout=timeout
        )
        return result.returncode == 0, result.stdout.strip(), result.stderr.strip()
    except subprocess.TimeoutExpired:
        return False, "", "Command timed out"
    except Exception as e:
        return False, "", str(e)


def log(message: str, level: str = "info") -> None:
    """Log a message with color coding."""
    colors = {
        "info": "\033[36m",  # Cyan
        "success": "\033[32m",  # Green
        "warning": "\033[33m",  # Yellow
        "error": "\033[31m",  # Red
        "header": "\033[35m",  # Magenta
        "reset": "\033[0m",  # Reset
    }

    icons = {
        "info": "ℹ️ ",
        "success": "✅ ",
        "warning": "⚠️ ",
        "error": "❌ ",
        "header": "🚀 ",
    }

    color = colors.get(level, colors["info"])
    icon = icons.get(level, "")
    reset = colors["reset"]

    print(f"{color}{icon}{message}{reset}")


class PrePublishValidator:
    """Comprehensive pre-publish validation."""

    def __init__(self):
        self.results = {}
        self.total_checks = 0
        self.passed_checks = 0

    def run_check(self, name: str, check_func) -> bool:
        """Run a validation check and track results."""
        self.total_checks += 1
        log(f"Running {name}...", "info")

        try:
            success = check_func()
            if success:
                log(f"{name} passed", "success")
                self.passed_checks += 1
            else:
                log(f"{name} failed", "error")

            self.results[name] = success
            return success
        except Exception as e:
            log(f"{name} error: {e}", "error")
            self.results[name] = False
            return False

    def check_version_consistency(self) -> bool:
        """Check that versions are consistent across files."""
        try:
            # Get package.json version
            with open("package.json") as f:
                package_data = json.load(f)
                package_version = package_data.get("version")

            # Get pyproject.toml version
            pyproject_content = Path("pyproject.toml").read_text()
            import re

            match = re.search(r'version\s*=\s*"([^"]+)"', pyproject_content)
            pyproject_version = match.group(1) if match else None

            if package_version != pyproject_version:
                log(
                    f"Version mismatch: package.json={package_version}, pyproject.toml={pyproject_version}",
                    "error",
                )
                return False

            log(f"Version consistency: {package_version}", "success")
            return True
        except Exception as e:
            log(f"Version check failed: {e}", "error")
            return False

    def check_required_files(self) -> bool:
        """Check that all required files exist."""
        required_files = [
            "package.json",
            "pyproject.toml",
            "README.md",
            "CHANGELOG.md",
            "LICENSE",
            "hotel_mcp.py",
            "bin/hotel-mcp.js",
            "src/database.py",
            "src/translations.py",
            "src/media.py",
            "src/resources.py",
            "src/monitoring.py",
            "src/cache.py",
        ]

        missing_files = []
        for file_path in required_files:
            if not Path(file_path).exists():
                missing_files.append(file_path)

        if missing_files:
            log(f"Missing required files: {missing_files}", "error")
            return False

        return True

    def check_python_tests(self) -> bool:
        """Run Python test suite."""
        success, stdout, stderr = run_command(
            "uv run pytest -x --tb=short", timeout=120
        )
        if not success:
            log(f"Python tests failed: {stderr}", "error")
        return success

    def check_distribution_tests(self) -> bool:
        """Run distribution test suite."""
        success, stdout, stderr = run_command(
            "python scripts/test_distribution.py", timeout=60
        )
        if not success:
            log(f"Distribution tests failed: {stderr}", "error")
        return success

    def check_code_formatting(self) -> bool:
        """Check code formatting with black."""
        success, stdout, stderr = run_command("uv run black --check .")
        if not success:
            log("Code formatting issues found. Run: uv run black .", "warning")
            # For now, just warn but don't fail
            return True
        return success

    def check_import_sorting(self) -> bool:
        """Check import sorting with isort."""
        success, stdout, stderr = run_command("uv run isort --check-only .")
        if not success:
            log("Import sorting issues found. Run: uv run isort .", "error")
        return success

    def check_linting(self) -> bool:
        """Check code linting with flake8."""
        success, stdout, stderr = run_command("uv run flake8")
        if not success:
            log(f"Linting issues found: {stderr}", "error")
        return success

    def check_npm_package(self) -> bool:
        """Validate NPM package configuration."""
        success, stdout, stderr = run_command("npm pack --dry-run")
        if not success:
            log(f"NPM package validation failed: {stderr}", "error")
        return success

    def check_git_status(self) -> bool:
        """Check git repository status."""
        # Check for uncommitted changes
        success, stdout, stderr = run_command("git status --porcelain")
        if stdout.strip():
            log(
                "Uncommitted changes detected. Commit all changes before publishing.",
                "error",
            )
            return False

        # Check if we're on main/master branch
        success, stdout, stderr = run_command("git branch --show-current")
        current_branch = stdout.strip()
        if current_branch not in ["main", "master"]:
            log(f"Not on main/master branch (current: {current_branch})", "warning")
            # Don't fail for this, just warn

        return True

    def check_documentation(self) -> bool:
        """Check documentation completeness."""
        # Check README.md has NPX instructions
        readme_content = Path("README.md").read_text()
        if "npx hotel-mcp" not in readme_content:
            log("README.md missing NPX instructions", "error")
            return False

        # Check CHANGELOG.md exists and has content
        changelog_content = Path("CHANGELOG.md").read_text()
        if len(changelog_content.strip()) < 100:
            log("CHANGELOG.md appears to be empty or too short", "error")
            return False

        return True

    def check_environment_variables(self) -> bool:
        """Check for sensitive environment variables."""
        # Check .env.example exists
        if not Path(".env.example").exists():
            log(".env.example file missing", "error")
            return False

        # Check that .env is in .gitignore
        gitignore_content = Path(".gitignore").read_text()
        if ".env" not in gitignore_content:
            log(".env not in .gitignore", "error")
            return False

        return True

    def check_license(self) -> bool:
        """Check license file exists and is valid."""
        license_file = Path("LICENSE")
        if not license_file.exists():
            log("LICENSE file missing", "error")
            return False

        license_content = license_file.read_text()
        if len(license_content.strip()) < 100:
            log("LICENSE file appears to be empty or too short", "error")
            return False

        return True

    def run_all_checks(self) -> bool:
        """Run all validation checks."""
        log("Hotel MCP - Pre-Publish Validation", "header")
        log("=" * 50, "info")

        checks = [
            ("Version Consistency", self.check_version_consistency),
            ("Required Files", self.check_required_files),
            ("Python Tests", self.check_python_tests),
            ("Distribution Tests", self.check_distribution_tests),
            ("Code Formatting", self.check_code_formatting),
            ("Import Sorting", self.check_import_sorting),
            ("Code Linting", self.check_linting),
            ("NPM Package", self.check_npm_package),
            ("Git Status", self.check_git_status),
            ("Documentation", self.check_documentation),
            ("Environment Variables", self.check_environment_variables),
            ("License", self.check_license),
        ]

        for check_name, check_func in checks:
            self.run_check(check_name, check_func)

        # Summary
        log("=" * 50, "info")
        log(
            f"Validation Summary: {self.passed_checks}/{self.total_checks} checks passed",
            "info",
        )

        if self.passed_checks == self.total_checks:
            log("🎉 All validation checks passed! Ready for publication.", "success")
            return True
        else:
            failed_count = self.total_checks - self.passed_checks
            log(
                f"❌ {failed_count} validation checks failed. Fix issues before publishing.",
                "error",
            )

            # Show failed checks
            failed_checks = [
                name for name, result in self.results.items() if not result
            ]
            log(f"Failed checks: {', '.join(failed_checks)}", "error")

            return False


def main():
    """Main validation workflow."""
    validator = PrePublishValidator()
    success = validator.run_all_checks()

    if success:
        log("\n📋 Next steps:", "info")
        log("1. Run: python scripts/release.py patch", "info")
        log("2. Or run: npm publish", "info")
        log("3. Verify: npx hotel-mcp@latest --help", "info")
        return 0
    else:
        log("\n🔧 Fix the issues above and run this script again.", "error")
        return 1


if __name__ == "__main__":
    sys.exit(main())
