;; Title: Miniforge.ai
;; Subtitle: An agentic SDLC / fleet-control platform
;; Author: Christopher Lester
;; Line: Founder, Miniforge.ai (project)
;; Copyright 2025-2026 Christopher Lester (christopher@miniforge.ai)
;;
;; Licensed under the Apache License, Version 2.0 (the "License");
;; you may not use this file except in compliance with the License.
;; You may obtain a copy of the License at
;;
;;     http://www.apache.org/licenses/LICENSE-2.0
;;
;; Unless required by applicable law or agreed to in writing, software
;; distributed under the License is distributed on an "AS IS" BASIS,
;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;; See the License for the specific language governing permissions and
;; limitations under the License.

(ns demo-security-compliance
  "Demo script — runs the full security-compliance workflow against fixtures.

   Usage (from the workflow-security-compliance component root):
     clj -M -m demo-security-compliance

   Or from a REPL:
     (require 'demo-security-compliance)
     (demo-security-compliance/-main)"
  (:require
   [clojure.java.io :as io]
   [clojure.pprint :as pp]
   [ai.miniforge.workflow-security-compliance.messages :as msg]
   [ai.miniforge.workflow-security-compliance.phases :as phases]
   [ai.miniforge.workflow-security-compliance.interface]))

;------------------------------------------------------------------------------ Helpers

(defn- separator [label]
  (let [separator-line "------------------------------------------------------------"]
    (println)
    (println separator-line)
    (println (str " " label))
    (println separator-line)
    (println)))

(defn- print-violation-summary [violations]
  (doseq [v violations]
    (let [rule-id (:violation/rule-id v)
          severity (name (:violation/severity v))
          message (:violation/message v)
          preview (subs message 0 (min 70 (count message)))]
      (println (format "  [%s] %-8s %s" rule-id severity preview)))))

(defn- print-classified [classified]
  (let [by-cat (group-by :classification/category classified)]
    (doseq [[cat items] (sort-by (comp str key) by-cat)]
      (let [category (name cat)
            item-count (count items)
            min-confidence (* 100.0 (apply min (map :classification/confidence items)))
            max-confidence (* 100.0 (apply max (map :classification/confidence items)))]
        (println (msg/t :demo/category-summary {:category category
                                                :count item-count
                                                :min min-confidence
                                                :max max-confidence})))
      (doseq [v items]
        (let [rule-id (:violation/rule-id v)
              file (get-in v [:violation/location :file] "?")
              doc-status (name (get v :classification/doc-status :unknown))]
          (println (msg/t :demo/category-item {:rule-id rule-id
                                               :file file
                                               :doc-status (if (= "unknown" doc-status)
                                                             (msg/t :demo/doc-status-unknown)
                                                             doc-status)})))))))

;------------------------------------------------------------------------------ Phase runner

(defn- run-phase
  "Thread `ctx` through a phase's enter/leave interceptors, stamping :started-at
   so the leave step can compute duration."
  [ctx enter-fn leave-fn]
  (-> ctx
      enter-fn
      (assoc-in [:phase :started-at] (System/currentTimeMillis))
      leave-fn))

(defn- phase-output
  [ctx phase-kw output-key]
  (get-in ctx [:execution/phase-results phase-kw :result :output output-key]))

;------------------------------------------------------------------------------ Context construction

(defn- demo-output-dir []
  (str (System/getProperty "java.io.tmpdir")
       "/miniforge-demo-" (System/currentTimeMillis)))

(defn- initial-context
  [output-dir]
  {:execution/id (random-uuid)
   :execution/input {:scan-paths ["test/ai/miniforge/workflow_security_compliance/fixture_files/sample-scan.sarif"
                                  "test/ai/miniforge/workflow_security_compliance/fixture_files/sample-scan.csv"]
                     :output-dir output-dir}
   :execution/metrics {:duration-ms 0}
   :execution/phase-results {}})

;------------------------------------------------------------------------------ Phase stages

(defn- stage-parse [ctx]
  (run-phase ctx phases/enter-sec-parse-scan phases/leave-sec-parse-scan))

(defn- stage-trace [ctx]
  (run-phase ctx phases/enter-sec-trace-source phases/leave-sec-trace-source))

(defn- stage-verify [ctx]
  (run-phase ctx phases/enter-sec-verify-docs phases/leave-sec-verify-docs))

(defn- stage-classify [ctx]
  (run-phase ctx phases/enter-sec-classify phases/leave-sec-classify))

(defn- stage-exclusions [ctx]
  (run-phase ctx phases/enter-sec-generate-exclusions phases/leave-sec-generate-exclusions))

;------------------------------------------------------------------------------ Section printers

(defn- print-parse-section [ctx violations]
  (separator (msg/t :demo/phase-parse))
  (println (msg/t :demo/parsed-summary
                  {:violations (count violations)
                   :files (count (get-in ctx [:execution/input :scan-paths]))}))
  (print-violation-summary violations))

(defn- print-trace-section [traced]
  (separator (msg/t :demo/phase-trace))
  (println (msg/t :demo/traced-summary
                  {:violations (count traced)
                   :dynamic (count (filter :trace/dynamic-load? traced))})))

(defn- print-verify-section [verified]
  (separator (msg/t :demo/phase-verify))
  (println (msg/t :demo/verified-summary
                  {:violations (count verified)
                   :documented (count (filter :verified/documented? verified))
                   :undocumented (count (remove :verified/documented? verified))})))

(defn- print-classify-section [classified metrics]
  (separator (msg/t :demo/phase-classify))
  (println (msg/t :demo/classification-results))
  (println (msg/t :demo/metric-true-positives {:count (:true-positives metrics 0)}))
  (println (msg/t :demo/metric-false-positives {:count (:false-positives metrics 0)}))
  (println (msg/t :demo/metric-needs-review {:count (:needs-review metrics 0)}))
  (println)
  (print-classified classified))

(defn- print-exclusions-section [excl-output excl-file]
  (separator (msg/t :demo/phase-exclusions))
  (println (msg/t :demo/excluded-summary {:count (:total-excluded excl-output 0)}))
  (println (msg/t :demo/flagged-summary {:count (:total-flagged excl-output 0)}))
  (println)
  (when (.exists excl-file)
    (println (msg/t :demo/exclusions-path {:path (.getAbsolutePath excl-file)}))
    (println)
    (println (msg/t :demo/exclusions-heading))
    (pp/pprint (:exclusion-list excl-output))))

(defn- category-count [classified category]
  (count (filter #(= category (:classification/category %)) classified)))

(defn- print-summary-section [ctx classified total-duration phases-done]
  (separator (msg/t :demo/phase-summary))
  (println (msg/t :demo/phases-completed {:count (count phases-done)}))
  (println (msg/t :demo/total-duration {:count total-duration}))
  (println (msg/t :demo/input-files
                  {:count (count (get-in ctx [:execution/input :scan-paths]))}))
  (println (msg/t :demo/total-violations {:count (count classified)}))
  (println (msg/t :demo/true-positives-summary
                  {:count (category-count classified :true-positive)}))
  (println (msg/t :demo/false-positives-summary
                  {:count (category-count classified :false-positive)}))
  (println (msg/t :demo/needs-review-summary
                  {:count (category-count classified :needs-investigation)}))
  (println)
  (println (msg/t :demo/complete)))

;------------------------------------------------------------------------------ Main

(defn -main
  "Run the 5-phase security compliance workflow against sample fixtures."
  [& _args]
  (separator (msg/t :demo/title))
  (let [output-dir       (demo-output-dir)
        ctx              (initial-context output-dir)
        after-parse      (stage-parse ctx)
        after-trace      (stage-trace after-parse)
        after-verify     (stage-verify after-trace)
        after-classify   (stage-classify after-verify)
        after-exclusions (stage-exclusions after-classify)
        violations       (phase-output after-parse :sec-parse-scan :violations)
        traced           (phase-output after-trace :sec-trace-source :traced-violations)
        verified         (phase-output after-verify :sec-verify-docs :verified-violations)
        classified       (phase-output after-classify :sec-classify :classified-violations)
        metrics          (get-in after-classify [:phase :metrics])
        excl-output      (get-in after-exclusions [:execution/phase-results
                                                   :sec-generate-exclusions
                                                   :result :output])
        excl-file        (io/file output-dir ".security-exclusions" "exclusions.edn")
        total-duration   (get-in after-exclusions [:execution/metrics :duration-ms] 0)
        phases-done      (get-in after-exclusions [:execution :phases-completed])]
    (print-parse-section ctx violations)
    (print-trace-section traced)
    (print-verify-section verified)
    (print-classify-section classified metrics)
    (print-exclusions-section excl-output excl-file)
    (print-summary-section ctx classified total-duration phases-done)))
