use std::path::Path;
use std::time::Instant;

use crate::error::Result;
use crate::models::{
    BenchmarkGateOptions, BenchmarkRunOptions, EvalRunOptions, ReleaseGateDecision,
    ReleaseGatePackOptions, ReleaseGatePackReport,
};
use crate::release_gate::{
    benchmark_release_gate_decision, eval_quality_gate_decision, evaluate_build_quality_gate,
    evaluate_contract_integrity_gate, finalize_release_gate_pack_report,
    operability_evidence_gate_decision, release_gate_pack_report_uri,
    reliability_evidence_gate_decision, resolve_workspace_dir, security_audit_gate_decision,
    session_memory_gate_decision,
};

use super::AxiomSync;
use super::benchmark_service::{
    RELEASE_BENCHMARK_SEED_EXPECTED_URI, RELEASE_BENCHMARK_SEED_QUERY,
    RELEASE_BENCHMARK_SEED_QUERY_STABLE, RELEASE_BENCHMARK_SEED_TARGET_URI,
};

impl AxiomSync {
    pub fn collect_release_gate_pack(
        &self,
        options: &ReleaseGatePackOptions,
    ) -> Result<ReleaseGatePackReport> {
        let request_id = uuid::Uuid::new_v4().to_string();
        let started = Instant::now();

        let output = (|| -> Result<ReleaseGatePackReport> {
            let workspace_path = resolve_workspace_dir(options.workspace_dir.as_deref())?;
            let workspace_dir = workspace_path.display().to_string();
            let decisions =
                self.collect_release_gate_decisions(&workspace_path, &workspace_dir, options)?;

            let pack_id = uuid::Uuid::new_v4().to_string();
            let report_uri = release_gate_pack_report_uri(&pack_id)?;
            let report = finalize_release_gate_pack_report(
                pack_id,
                workspace_dir,
                decisions,
                report_uri.to_string(),
            );
            self.fs
                .write(&report_uri, &serde_json::to_string_pretty(&report)?, true)?;
            Ok(report)
        })();

        match output {
            Ok(report) => {
                self.log_request_status(
                    request_id,
                    "release.pack",
                    report.status.as_str(),
                    started,
                    None,
                    Some(serde_json::json!({
                        "workspace_dir": report.workspace_dir,
                        "passed": report.passed,
                        "unresolved_blockers": report.unresolved_blockers,
                        "report_uri": report.report_uri,
                    })),
                );
                Ok(report)
            }
            Err(err) => {
                self.log_request_error(request_id, "release.pack", started, None, &err, None);
                Err(err)
            }
        }
    }

    fn collect_release_gate_decisions(
        &self,
        workspace_path: &Path,
        workspace_dir: &str,
        options: &ReleaseGatePackOptions,
    ) -> Result<Vec<ReleaseGateDecision>> {
        let mut decisions = Vec::<ReleaseGateDecision>::new();

        decisions.push(evaluate_contract_integrity_gate(workspace_path));
        decisions.push(evaluate_build_quality_gate(workspace_path));

        let reliability = self.collect_reliability_evidence(
            options.replay.replay_limit.max(1),
            options.replay.replay_max_cycles.max(1),
        )?;
        decisions.push(reliability_evidence_gate_decision(&reliability));

        self.ensure_release_benchmark_seed_trace()?;
        let _ = self.add_eval_golden_query(
            RELEASE_BENCHMARK_SEED_QUERY,
            Some(RELEASE_BENCHMARK_SEED_TARGET_URI),
            Some(RELEASE_BENCHMARK_SEED_EXPECTED_URI),
        )?;
        let _ = self.add_eval_golden_query(
            RELEASE_BENCHMARK_SEED_QUERY_STABLE,
            Some(RELEASE_BENCHMARK_SEED_TARGET_URI),
            Some(RELEASE_BENCHMARK_SEED_EXPECTED_URI),
        )?;

        let eval = self.run_eval_loop_with_options(&EvalRunOptions {
            trace_limit: options.eval.eval_trace_limit.max(1),
            query_limit: options.eval.eval_query_limit.max(1),
            search_limit: options.eval.eval_search_limit.max(1),
            include_golden: true,
            golden_only: true,
        })?;
        decisions.push(eval_quality_gate_decision(&eval));

        let (g4_passed, memory_category_miss, g4_details) = self.evaluate_session_memory_gate()?;
        decisions.push(session_memory_gate_decision(
            g4_passed,
            memory_category_miss,
            &g4_details,
        ));

        let security = self.run_security_audit_with_mode(
            Some(workspace_dir),
            Some(options.security_audit_mode.as_str()),
        )?;
        decisions.push(security_audit_gate_decision(&security));

        let _ = self.run_benchmark_suite(&BenchmarkRunOptions {
            query_limit: options.benchmark_run.benchmark_query_limit.max(1),
            search_limit: options.benchmark_run.benchmark_search_limit.max(1),
            include_golden: true,
            include_trace: false,
            include_stress: false,
            trace_expectations: true,
            fixture_name: None,
        })?;
        let benchmark_gate = self.benchmark_gate_with_options(BenchmarkGateOptions {
            gate_profile: "rc-candidate".to_string(),
            threshold_p95_ms: options.benchmark_gate.benchmark_threshold_p95_ms,
            min_top1_accuracy: options.benchmark_gate.benchmark_min_top1_accuracy,
            min_stress_top1_accuracy: options.benchmark_gate.benchmark_min_stress_top1_accuracy,
            max_p95_regression_pct: options.benchmark_gate.benchmark_max_p95_regression_pct,
            max_top1_regression_pct: options.benchmark_gate.benchmark_max_top1_regression_pct,
            window_size: options.benchmark_gate.benchmark_window_size.max(1),
            required_passes: options.benchmark_gate.benchmark_required_passes.max(1),
            record: true,
            write_release_check: false,
        })?;
        decisions.push(benchmark_release_gate_decision(&benchmark_gate));

        let operability = self.collect_operability_evidence(
            options.operability.trace_limit.max(1),
            options.operability.request_limit.max(1),
        )?;
        decisions.push(operability_evidence_gate_decision(&operability));

        Ok(decisions)
    }
}
