import argparse
import logging
import sys
from pathlib import Path
from typing import List, Optional

from .gui.localization import localization
from .license.runtime_bridge import get_license_bridge, initialize_license_system
from .model import Finding, ScanRequest
from .reporting import HistoryStore, ReportEngine
from .scanner import SentinelScanner
from .subscription import SubscriptionTier

LANGUAGE_CHOICES = tuple(localization.get_available_languages().keys())


def build_parser() -> argparse.ArgumentParser:
    history_default = str(Path.home() / ".web-sentinel" / "history.json")
    log_default = str(Path.home() / ".web-sentinel" / "web-sentinel.log")

    parser = argparse.ArgumentParser(
        description=localization.t("cli_description")
    )
    parser.add_argument("domain", help=localization.t("cli_arg_domain"))
    parser.add_argument(
        "--language",
        choices=LANGUAGE_CHOICES,
        default=localization.get_current_language(),
        help=localization.t("cli_arg_language").format(default=localization.get_current_language()),
    )
    parser.add_argument(
        "--http-port",
        type=int,
        default=80,
        help=localization.t("cli_arg_http_port").format(default=80),
    )
    parser.add_argument(
        "--https-port",
        type=int,
        default=443,
        help=localization.t("cli_arg_https_port").format(default=443),
    )
    parser.add_argument(
        "--timeout",
        type=float,
        default=5.0,
        help=localization.t("cli_arg_timeout").format(default=5.0),
    )
    parser.add_argument(
        "--allow-invasive",
        action="store_true",
        help=localization.t("cli_arg_allow_invasive"),
    )
    parser.add_argument(
        "--json",
        action="store_true",
        dest="as_json",
        help=localization.t("cli_arg_json"),
    )
    parser.add_argument(
        "--json-report",
        type=str,
        help=localization.t("cli_arg_json_report"),
    )
    parser.add_argument(
        "--html-report",
        type=str,
        help=localization.t("cli_arg_html_report"),
    )
    parser.add_argument(
        "--modules",
        nargs="+",
        help=localization.t("cli_arg_modules"),
    )
    parser.add_argument(
        "--history-file",
        type=str,
        default=history_default,
        help=localization.t("cli_arg_history_file").format(default=history_default),
    )
    parser.add_argument(
        "--no-history",
        action="store_true",
        help=localization.t("cli_arg_no_history"),
    )
    parser.add_argument(
        "--log-file",
        type=str,
        default=log_default,
        help=localization.t("cli_arg_log_file").format(default=log_default),
    )
    
    # SAST (Source Code Analysis) arguments
    parser.add_argument(
        "--source-path",
        type=str,
        help="Path to source code directory or file for static analysis (requires PRO+ license)",
    )
    parser.add_argument(
        "--source-languages",
        nargs="+",
        choices=['php', 'javascript', 'python', 'java', 'csharp', 'go', 'auto'],
        default=['auto'],
        help="Programming languages to scan (default: auto-detect)",
    )
    parser.add_argument(
        "--source-exclude",
        nargs="+",
        default=[],
        help="Patterns to exclude from source code scanning (e.g., vendor/ node_modules/)",
    )
    parser.add_argument(
        "--severity-min",
        choices=['info', 'low', 'medium', 'high', 'critical'],
        default='medium',
        help="Minimum severity level to report (default: medium)",
    )
    
    return parser


def main(argv: Optional[List[str]] = None) -> int:
    pre_parser = argparse.ArgumentParser(add_help=False)
    pre_parser.add_argument("--language", choices=LANGUAGE_CHOICES)
    pre_args, _ = pre_parser.parse_known_args(argv)
    if pre_args.language:
        localization.set_language(pre_args.language)

    parser = build_parser()
    args = parser.parse_args(argv)
    localization.set_language(args.language)

    _configure_logging(args.log_file)
    
    # 🔐 PRIORITÉ 1 : Validation licence au démarrage CLI
    logging.info("🔐 Initialisation du système de licence...")
    license_bridge = get_license_bridge()
    license_init_success = initialize_license_system()

    from .auth.auth_manager import AuthManager

    auth_manager = AuthManager()
    subscription_manager = auth_manager.get_subscription_manager()
    current_user = auth_manager.get_current_user()
    owner_email = current_user.email if current_user else None

    license_init_success = license_bridge.apply_subscription(subscription_manager.tier, owner_email)
    license_status = license_bridge.get_license_status()

    is_sysop = subscription_manager.tier == SubscriptionTier.SYSOP

    if license_init_success:
        logging.info(localization.t("cli_license_loaded", license_status.get("tier", "FREE")))
    else:
        if not is_sysop:  # Ne pas afficher l'erreur pour SysOp
            logging.warning(localization.t("cli_license_fallback"))

    alert_level = license_status.get("alert_level")
    threshold = license_status.get("alert_threshold")
    if alert_level == "CRITICAL" and not is_sysop:  # Ignorer les alertes pour SysOp
        if not license_status.get("valid", True):
            logging.error(localization.t("license_status_expired"))
        else:
            logging.error(localization.t("license_status_critical", threshold or 0))
    elif alert_level == "WARNING" and not is_sysop:
        logging.warning(localization.t("license_status_warning", threshold or 0))
    elif alert_level == "INFO" and not is_sysop:
        logging.info(localization.t("license_status_info", threshold or 0))

    features_enabled = license_status.get("features_enabled", {})
    if args.allow_invasive and not features_enabled.get("invasive_tests", False):
        logging.error(localization.t("cli_invasive_not_allowed"))
        args.allow_invasive = False

    if args.html_report and not features_enabled.get("html_export", False):
        logging.error(localization.t("cli_html_not_allowed"))
        return 2

    # Check SAST permissions if source scanning is requested
    if args.source_path and not features_enabled.get("source_scan", False):
        logging.error("❌ Source code scanning requires PRO license or higher")
        logging.info("💡 Upgrade your license to access SAST features")
        return 2

    sast_kwargs = {}
    if args.source_path:
        languages = tuple(args.source_languages or ["auto"])
        exclude = tuple(args.source_exclude or [])
        sast_kwargs = {
            "source_path": args.source_path,
            "source_languages": languages,
            "source_exclude": exclude,
            "source_min_severity": args.severity_min,
            "source_max_files": license_status.get("max_source_files", -1),
            "source_max_size_mb": license_status.get("max_source_size_mb", -1),
            "source_advanced_rules": features_enabled.get("advanced_rules", False),
        }

    request = ScanRequest(
        domain=args.domain,
        http_port=args.http_port,
        https_port=args.https_port,
        timeout=args.timeout,
        allow_invasive=args.allow_invasive,
        **sast_kwargs,
    )

    scanner = SentinelScanner()

    enabled_modules = args.modules
    if enabled_modules:
        available = set(scanner.modules)
        unknown = [module for module in enabled_modules if module not in available]
        if unknown:
            logging.warning(localization.t("cli_unknown_modules_warning").format(", ".join(unknown)))
        enabled_modules = [module for module in enabled_modules if module in available]

    result = scanner.run(request, enabled_modules=enabled_modules)

    history_store = None if args.no_history else HistoryStore(Path(args.history_file))
    report_engine = ReportEngine(history_store=history_store)
    context = report_engine.build_context(result)

    if context["regressions"]:
        labels = _format_labels(context["regressions"])
        logging.warning(localization.t("regressions_detected").format(len(context["regressions"]), labels))
    else:
        logging.info(localization.t("no_regressions"))

    if context["resolved"]:
        labels = _format_labels(context["resolved"])
        logging.info(localization.t("fixes_confirmed").format(len(context["resolved"]), labels))

    if history_store:
        history_store.record(result)

    if args.as_json:
        print(report_engine.render_json(context))
        _write_side_reports(report_engine, context, args)
        return 0

    if not result.findings:
        print(localization.t("no_findings"))
        _write_side_reports(report_engine, context, args)
        return 0

    for finding in result.findings:
        translated = localization.translate_finding_content(finding)
        severity_label = localization.translate_severity(finding.severity)
        module_label = _module_label(finding.check)
        title = getattr(translated, "title", finding.title)
        description = getattr(translated, "description", finding.description)
        remediation = getattr(translated, "remediation", finding.remediation)
        evidence = getattr(translated, "evidence", finding.evidence)
        impact = getattr(translated, "impact", finding.impact)

        print(f"[{severity_label}] {module_label} - {title}")
        print(f"  {localization.t('finding_description')}: {description}")
        print(f"  {localization.t('finding_remediation')}: {remediation}")
        if evidence:
            print(f"  {localization.t('finding_evidence')}: {evidence}")
        if impact:
            print(f"  {localization.t('finding_impact')}: {impact}")
        print()

    _write_side_reports(report_engine, context, args)

    return 0


def _write_side_reports(report_engine: ReportEngine, context: dict, args: argparse.Namespace) -> None:
    if args.json_report:
        path = Path(args.json_report)
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(report_engine.render_json(context), encoding="utf-8")
        logging.info(localization.t("cli_json_saved").format(path))

    if args.html_report:
        path = Path(args.html_report)
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(
            report_engine.render_html(context, language=localization.get_current_language()),
            encoding="utf-8",
        )
        logging.info(localization.t("cli_html_saved").format(path))


def _module_label(module: str) -> str:
    module_key = f"module_{module.replace('-', '_')}"
    label = localization.translate_module(module)
    return label if label != module_key else module


def _format_labels(entries: List[dict]) -> str:
    labels: List[str] = []
    for entry in entries:
        finding = Finding(
            check=entry["check"],
            title=entry["title"],
            severity=entry["severity"],
            description=entry["description"],
            remediation=entry["remediation"],
            impact=entry.get("impact"),
            evidence=entry.get("evidence"),
            i18n_key=entry.get("i18n_key"),
            i18n_params=entry.get("i18n_params"),
        )
        translated = localization.translate_finding_content(finding)
        labels.append(f"{_module_label(finding.check)}::{getattr(translated, 'title', finding.title)}")
    return ", ".join(labels)


def _configure_logging(log_path: Optional[str]) -> None:
    logger = logging.getLogger()
    logger.handlers.clear()
    logger.setLevel(logging.INFO)

    console_handler = logging.StreamHandler()
    console_handler.setFormatter(logging.Formatter("[%(asctime)s] %(levelname)s %(name)s: %(message)s"))
    logger.addHandler(console_handler)

    if log_path:
        path = Path(log_path)
        path.parent.mkdir(parents=True, exist_ok=True)
        file_handler = logging.FileHandler(path, encoding="utf-8")
        file_handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(name)s %(message)s"))
        logger.addHandler(file_handler)


if __name__ == "__main__":  # pragma: no cover
    sys.exit(main())
