;; 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 ai.miniforge.release-executor.metadata-test
  (:require
   [ai.miniforge.release-executor.metadata :as metadata]
   [clojure.string :as str]
   [clojure.test :refer [deftest is testing]]))

(deftest slugify-uses-message-defaults
  (testing "nil input falls back to the configured default slug seed"
    (is (= "change" (metadata/slugify nil)))))

(deftest fallback-release-metadata-renders-resource-backed-body
  (testing "fallback metadata uses the release-executor message catalog"
    (let [result (metadata/fallback-release-metadata
                  "Add release metadata strings"
                  [{:code/files [{:path "src/feature.clj" :action :create}
                                 {:path "README.md" :action :modify}]}])
          body (:release/pr-body result)]
      (is (= "Add release metadata strings" (:release/commit-message result)))
      (is (str/includes? body "## Summary\n\nAdd release metadata strings\n\n"))
      (is (str/includes? body "## Changes\n\n- `src/feature.clj` (create)\n- `README.md` (modify)\n\n"))
      (is (str/includes? body "## Test plan\n\n- [ ] Verify changes compile and tests pass\n- [ ] Review generated code for correctness\n\n"))
      (is (str/ends-with? body "---\nGenerated by Miniforge SDLC workflow (2 files)")))))

(deftest fallback-release-metadata-uses-default-description
  (testing "fallback metadata uses the configured default description when none is provided"
    (let [result (metadata/fallback-release-metadata nil [{:code/files []}])
          body (:release/pr-body result)]
      (is (= "implement changes" (:release/commit-message result)))
      (is (not (str/includes? body "## Changes")))
      (is (str/starts-with? body "## Summary\n\nimplement changes\n\n"))
      (is (str/ends-with? body "---\nGenerated by Miniforge SDLC workflow (0 files)")))))

(deftest fallback-release-metadata-with-review-artifacts
  (testing "fallback metadata includes review summary when review artifacts are provided"
    (let [review-artifact {:review/id (random-uuid)
                           :review/decision :approved
                           :review/summary "Code looks clean, well-structured with proper error handling."
                           :review/gate-results [{:gate/name "lint" :gate/status :passed}
                                                 {:gate/name "tests" :gate/status :passed}
                                                 {:gate/name "security" :gate/status :passed}]
                           :review/gates-passed 3
                           :review/gates-failed 0
                           :review/gates-total 3}
          workflow-data {:review-artifacts [review-artifact]}
          result (metadata/fallback-release-metadata
                  "Add new feature for user auth"
                  [{:code/files [{:path "src/auth.clj" :action :create}]}]
                  workflow-data)
          body (:release/pr-body result)]
      (is (str/includes? body "## Review"))
      (is (str/includes? body "**Decision**: approved"))
      (is (str/includes? body "Code looks clean, well-structured with proper error handling."))
      (is (str/includes? body "**Quality gates**: 3/3 passed"))
      (is (str/includes? body "✅ lint"))
      (is (str/includes? body "✅ tests"))
      (is (str/includes? body "✅ security")))))

(deftest fallback-release-metadata-with-failed-gates
  (testing "fallback metadata shows failed gate status correctly"
    (let [review-artifact {:review/id (random-uuid)
                           :review/decision :conditionally-approved
                           :review/summary "Minor issues found but acceptable."
                           :review/gate-results [{:gate/name "lint" :gate/status :passed}
                                                 {:gate/name "tests" :gate/status :failed}
                                                 {:gate/name "security" :gate/status :passed}]
                           :review/gates-passed 2
                           :review/gates-failed 1
                           :review/gates-total 3}
          workflow-data {:review-artifacts [review-artifact]}
          result (metadata/fallback-release-metadata
                  "Fix auth bug"
                  [{:code/files [{:path "src/auth.clj" :action :modify}]}]
                  workflow-data)
          body (:release/pr-body result)]
      (is (str/includes? body "**Quality gates**: 2/3 passed"))
      (is (str/includes? body "❌ tests"))
      (is (str/includes? body "✅ lint")))))

(deftest fallback-release-metadata-without-workflow-data
  (testing "fallback metadata works identically to 2-arity when no workflow data"
    (let [result-2 (metadata/fallback-release-metadata
                    "Simple change" [{:code/files [{:path "a.clj" :action :create}]}])
          result-3 (metadata/fallback-release-metadata
                    "Simple change" [{:code/files [{:path "a.clj" :action :create}]}] nil)]
      ;; Bodies should be structurally identical (branch names differ due to UUID)
      (is (= (:release/pr-body result-2) (:release/pr-body result-3)))
      (is (= (:release/commit-message result-2) (:release/commit-message result-3))))))

(deftest fallback-title-smart-truncation
  (testing "title truncates at word boundary when over 70 chars"
    (let [long-desc (str "Implement comprehensive release metadata generation with "
                         "structured PR body sections and smart truncation logic")
          result (metadata/fallback-release-metadata
                  long-desc [{:code/files [{:path "a.clj" :action :create}]}])
          title (:release/pr-title result)]
      (is (<= (count title) 73))  ;; 70 + "..."
      (is (str/ends-with? title "..."))
      (is (not (str/ends-with? (subs title 0 (- (count title) 3)) " "))))))

(deftest extract-review-artifacts-filters-correctly
  (testing "extracts review content from mixed artifact types"
    (let [artifacts [{:artifact/type :code :artifact/content {:code/files []}}
                     {:artifact/type :review :artifact/content {:review/decision :approved
                                                                :review/summary "LGTM"}}
                     {:type :test :content {:test/results :passed}}
                     {:artifact/type :review :artifact/content {:review/decision :rejected
                                                                :review/summary "Needs work"}}]
          result (metadata/extract-review-artifacts artifacts)]
      (is (= 2 (count result)))
      (is (= :approved (:review/decision (first result))))
      (is (= :rejected (:review/decision (second result)))))))

(deftest extract-test-artifacts-filters-correctly
  (testing "extracts test content from mixed artifact types"
    (let [artifacts [{:artifact/type :code :artifact/content {:code/files []}}
                     {:type :test :content {:test/results :passed}}
                     {:artifact/type :review :artifact/content {:review/decision :approved}}]
          result (metadata/extract-test-artifacts artifacts)]
      (is (= 1 (count result)))
      (is (= :passed (:test/results (first result)))))))
