;; Title: Miniforge.ai
;; Copyright 2025-2026 Christopher Lester (christopher@miniforge.ai)
;; Licensed under the Apache License, Version 2.0

(ns ai.miniforge.cli.main.commands.init
  "Init command — analyze a repository and write .miniforge/config.edn.

   Stratification (intra-namespace):
   Layer 0 — pure data + helpers with no in-ns deps.
   Layer 1 — `config-path` composes the L0 path constants.
   Layer 2 — `write-config!` composes Layer 1.
   Layer 3 — `init-cmd` (public CLI entry)."
  (:require
   [babashka.fs :as fs]
   [clojure.pprint :as pprint]
   [ai.miniforge.cli.main.display :as display]
   [ai.miniforge.cli.messages :as messages]
   [ai.miniforge.cli.repo-analyzer :as analyzer]))

;------------------------------------------------------------------------------ Layer 0
;; Pure data + helpers with no in-namespace dependencies.

(def ^:private config-dir ".miniforge")
(def ^:private config-file "config.edn")

(defn- format-config
  "Format a repo config map as pretty-printed EDN with a header comment."
  [config]
  (str ";; Miniforge repository configuration\n"
       ";; Generated by `bb miniforge init` — edit as needed.\n"
       ";; See: work/repo-config-profile.spec.edn\n\n"
       (with-out-str (pprint/pprint config))))

(defn- build-config
  "Build the .miniforge/config.edn map from analysis results."
  [analysis]
  (cond-> {:repo/technologies (:technologies analysis)
           :repo/packs        (:packs analysis)}
    (:git-host analysis)
    (assoc :repo/host (:git-host analysis))))

(defn- print-analysis
  "Print the analysis results to the user."
  [analysis]
  (display/print-info (messages/t :init/analysis-technologies
                                  {:value (pr-str (:technologies analysis))}))
  (display/print-info (messages/t :init/analysis-git-host
                                  {:value (or (:git-host analysis)
                                              (messages/t :init/git-host-unknown))}))
  (display/print-info (messages/t :init/analysis-packs
                                  {:value (pr-str (:packs analysis))})))

;------------------------------------------------------------------------------ Layer 1
;; Composes Layer 0 path constants.

(def ^:private config-path (str config-dir "/" config-file))

;------------------------------------------------------------------------------ Layer 2
;; Composes Layer 1.

(defn- write-config!
  "Write the config file. Returns the path written."
  [repo-path config]
  (let [dir  (fs/path repo-path config-dir)
        path (fs/path repo-path config-path)]
    (fs/create-dirs dir)
    (spit (str path) (format-config config))
    (str path)))

;------------------------------------------------------------------------------ Layer 3
;; Command entry point

(defn init-cmd
  "CLI entry point for the init command."
  [opts]
  (let [repo-path (get opts :repo (str (fs/cwd)))]
    (cond
      (not (fs/exists? repo-path))
      (display/print-error (messages/t :init/repo-not-found {:path repo-path}))

      :else
      (do
        (display/print-info (messages/t :init/analyzing {:path repo-path}))
        (let [analysis (analyzer/analyze-repo repo-path)
              config   (build-config analysis)
              exists?  (fs/exists? (fs/path repo-path config-path))]

          (print-analysis analysis)

          (when exists?
            (display/print-info (messages/t :init/existing-overwritten
                                            {:path config-path})))

          (let [written (write-config! repo-path config)]
            (display/print-info (messages/t :init/wrote {:path written}))))))))
