/*
 * Copyright 2026, Jaime Terrats.
 *
 * 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.
 */
import { workflow } from '../workflow-generator.js';
export function generateDevopsWorkflows(version) {
    return {
        'release.md': workflow(version, 'Create Release', `
## 1. Gather Release Scope

Ask:
- Target environment (sandbox / staging / production)
- Version number (semantic versioning: MAJOR.MINOR.PATCH)

Check merged branches since last release:

\`\`\`bash
git log --oneline <last-tag>..HEAD --merges
\`\`\`

## 2. Build Changelog

Extract commit messages grouped by type (feat, fix, chore):

\`\`\`bash
git log --oneline <last-tag>..HEAD
\`\`\`

Create or update \`CHANGELOG.md\` with the new version section.

## 3. Bump Version

Update \`sfdx-project.json\` → \`sourceApiVersion\` if needed, and version in \`package.json\`.

\`\`\`bash
npm version <major|minor|patch> --no-git-tag-version
\`\`\`

## 4. Validate and Tag

\`\`\`bash
sf project deploy validate -d force-app --target-org <staging-alias> --test-level RunLocalTests
\`\`\`

**IMPORTANT — Active Monitoring:** Wait for validation to complete before tagging.
Poll with \`sf project deploy report\` if needed. Only tag after successful validation.

\`\`\`bash
git tag -a v<version> -m "Release v<version>"
git push origin v<version>
\`\`\`
`),
        'destructive-deploy.md': workflow(version, 'Deploy Destructive Changes', `
## Overview

Destructive changes permanently delete metadata from an org.
Two XML files control when deletion happens relative to the deploy:

| File | Timing | Use when |
|------|--------|----------|
| \`preDestructiveChanges.xml\` | Before the deploy | The component blocks incoming changes (e.g. delete a field before renaming it, remove a validation rule that would reject new data) |
| \`postDestructiveChanges.xml\` | After the deploy | Clean up obsolete components once new code is live (e.g. remove old trigger after new handler is deployed) |

> ⚠️ **Always get explicit sign-off before proceeding.** Present the list of
> components to be deleted and the chosen timing (pre/post) and wait for approval.

## 1. Identify Components to Delete

Ask:
- **What** metadata type and API name must be deleted?
- **Why** is it being deleted? (retired feature, rename, refactor)
- **Timing:** Does anything in the incoming deploy depend on this component
  being gone *first* (pre), or can it be cleaned up *after* (post)?

## 2. Create the Destructive XML File(s)

Create \`manifest/preDestructiveChanges.xml\` and/or
\`manifest/postDestructiveChanges.xml\` as needed:

\`\`\`xml
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>ObjectName.FieldName</members>
        <name>CustomField</name>
    </types>
    <version>62.0</version>
</Package>
\`\`\`

Common metadata type names: \`CustomField\`, \`CustomObject\`, \`ApexClass\`,
\`ApexTrigger\`, \`Flow\`, \`ValidationRule\`, \`Layout\`, \`PermissionSet\`.

## 3. Validate Before Deleting (Mandatory)

\`\`\`bash
sf project deploy validate \\
  -x manifest/package.xml \\
  --pre-destructive-changes manifest/preDestructiveChanges.xml \\
  --post-destructive-changes manifest/postDestructiveChanges.xml \\
  --target-org <alias> \\
  --test-level RunLocalTests
\`\`\`

Wait for validation to complete. Never proceed to step 4 if validation fails.

## 4. Deploy with Destructive Changes

\`\`\`bash
sf project deploy start \\
  -x manifest/package.xml \\
  --pre-destructive-changes manifest/preDestructiveChanges.xml \\
  --post-destructive-changes manifest/postDestructiveChanges.xml \\
  --target-org <alias> \\
  --purge-on-delete
\`\`\`

> ⚠️ **\`--purge-on-delete\` is for sandboxes only.** Never use it against
> production — deleted records are not sent to the recycle bin and cannot
> be recovered. Omit the flag on production deploys.

## 5. Verify Deletion

After deploy completes, confirm the component no longer exists:

\`\`\`bash
sf org open --target-org <alias>
\`\`\`

Navigate to Setup and verify the deleted metadata is gone.
Report the result to the developer/configurator before closing the task.
`),
        'pr-review.md': workflow(version, 'Pull Request Review & Merge Conflict Resolution', `
## 1. Read the Full Diff

Never review from memory. Fetch the actual diff first:

\`\`\`bash
# Via GitHub CLI (preferred)
gh pr view <number> --json title,body,baseRefName,headRefName,files
gh pr diff <number>

# Via git (when working locally)
git fetch origin
git diff origin/<base>...origin/<head>
\`\`\`

Read every changed file. Metadata-heavy PRs may have XML changes that look
trivial but hide breaking schema changes — read those carefully.

## 2. Check for Conflicts

\`\`\`bash
git fetch origin
git checkout <feature-branch>
git merge --no-commit --no-ff origin/<base-branch>
git diff --name-only --diff-filter=U
\`\`\`

If conflicts exist, resolve them in Step 3 before continuing the review.

## 3. Resolve Conflicts (if any)

For each conflicted file:

1. Show the full conflict section — both \`<<<<<<< ours\` and \`>>>>>>> theirs\` blocks
2. Identify what each side changed and why (use \`git log --oneline\` per file if needed)
3. Propose the merged version with explicit reasoning:
   - **Keep ours** — their change is superseded or conflicts with a more recent decision
   - **Keep theirs** — our version is outdated or already fixed in their branch
   - **Merge both** — both changes are valid and must coexist

### Salesforce-Specific Conflict Rules

| File Type | Strategy |
|-----------|----------|
| \`.cls\` / \`.trigger\` | Merge manually — never discard test methods or trigger handler delegates |
| \`.flow-meta.xml\` | Flag for human review — Flow XML conflicts must be resolved in Flow Builder |
| \`-meta.xml\` (field/object) | Merge all \`<fields>\` entries from both sides |
| \`PermissionSet / Profile\` | Include all \`<fieldPermissions>\`, \`<objectPermissions>\` from both sides |
| \`package.xml\` | Union of both member lists; no duplicates |
| \`sfdx-project.json\` | Preserve \`packageDirectories\` from both; verify \`sourceApiVersion\` |

4. After resolving all conflicts:

\`\`\`bash
git add <resolved-files>
git merge --continue
\`\`\`

5. Re-validate before marking resolved:

\`\`\`bash
sf project deploy validate -d force-app --target-org <sandbox-alias> --test-level RunLocalTests
\`\`\`

## 4. Architectural Scope Detection (BLOCKING GATE)

Scan the diff for any of the following triggers. If ANY match,
**stop and block the merge** — the Architect must review before it can proceed.

| Trigger | How to detect |
|---------|---------------|
| 2+ Salesforce objects touched | \`objects/\` directory changes, new \`__c\` fields across multiple objects |
| Integration components modified | \`namedCredentials/\`, \`externalServices/\`, Platform Event definitions, CDC configs |
| Sharing model changes | \`sharing\` keyword in Apex, OWD in object metadata, sharing rules, PSG or PermissionSet changes |
| Package boundary changes | \`sfdx-project.json\` \`packageDirectories\` modified |
| Data migration or destructive deletes | \`destructiveChanges.xml\` with object/field deletions |
| Uncertainty | When in doubt, escalate — it is always safe to ask |

**If architectural scope is detected:**
> 🚨 **Architect Sign-Off Required**
> This PR contains changes that require architectural review before merge.
> Share this review with the Architect and wait for their explicit approval.
> Do not merge until the Architect confirms.

## 5. Checklist Review

Work through each item and report ✅ pass / ❌ fail / — N/A:

- [ ] No SOQL or DML inside loops
- [ ] No hardcoded IDs, org-specific endpoints, or credentials
- [ ] Apex classes use \`with sharing\` (exceptions documented)
- [ ] Test classes: \`@TestSetup\`, \`System.runAs()\`, exactly one Assert per method
- [ ] Code coverage ≥ 90%
- [ ] Destructive changes have explicit sign-off
- [ ] Branch name includes Backlog Item ID
- [ ] CI pipeline passed
- [ ] Architectural scope assessed — escalated to Architect if triggered

## 6. Produce Review Comment

Output a structured review comment:

\`\`\`markdown
## PR Review — <feature title>

**Summary:** <2–3 sentence description of what the PR does>

**Risk:** <Low / Medium / High> — <reason>

**Architectural Scope:** <None detected | 🚨 Requires Architect sign-off — <trigger reason>>

### Checklist
<paste checklist with ✅ / ❌ / —>

### Conflicts
<list resolved conflicts, or "None">

### Notes
<inline comments on specific files/lines if needed>

### Verdict
🔄 Request Changes | 💬 Needs Discussion | ⏳ Awaiting Architect Sign-Off | ✅ Ready for Human Approval
<reason>
\`\`\`

Post the review via GitHub CLI (review only — never merge without human confirmation):

\`\`\`bash
gh pr review <number> --comment --body "<comment>"
# or, to formally request changes:
gh pr review <number> --request-changes --body "<comment>"
\`\`\`

## 7. Human Approval Gate (MANDATORY — NEVER SKIP)

**The agent never merges a PR on its own authority.**

After posting the review, always end with one of:

- Standard: *"Review complete. Merge is ready pending your approval — reply 'approve' or 'merge' to proceed."*
- Architect required: *"Architect sign-off is required before this can merge. Share this review, and let me know once they approve."*
- Changes requested: *"Changes requested (see above). Once addressed, re-run the review before merging."*

Only after receiving explicit human confirmation execute the merge:

\`\`\`bash
gh pr merge <number> --squash --delete-branch
\`\`\`
`),
        'candidate-release.md': workflow(version, 'Candidate Release', `
## Overview

This workflow gates a release on **story readiness** before touching any org.
It is the formal entry point for every production release.

Sequence: **Story Gate → Changelog → Smart-Deploy Analyze → Validate → Tag → Deploy → Smoke Test**

---

## 1. Detect Issue Tracker

Check which tracker the project uses, in this order:

1. **Jira MCP** — if the \`jira\` MCP server is available in the session, use it.
2. **GitHub Issues** — if the repo has a GitHub remote, fall back to \`gh\` CLI.
3. **User-defined** — if neither is available, ask:
   > *"Which issue tracker are you using? (Jira project key / GitHub milestone / other)"*

Store the tracker type for use in Steps 2–4.

---

## 2. Collect Stories for This Release

### Jira

\`\`\`
jira_search: project = <KEY> AND fixVersion = "<version>" AND issuetype in (Story, Bug) ORDER BY priority ASC
\`\`\`

### GitHub Issues

\`\`\`bash
gh issue list --milestone "<milestone>" --state all --json number,title,state,labels
\`\`\`

List every story/issue and its current status. Present as a table:

| ID | Title | Status | Blocker? |
|----|-------|--------|----------|
| … | … | … | … |

---

## 3. Story Readiness Gate (Per Story)

For **each** story in the release scope, verify all criteria.
Mark each ✅ pass / ❌ fail / — N/A.

| # | Criterion | How to verify |
|---|-----------|---------------|
| 1 | **Acceptance Criteria complete** | All AC items checked off in the ticket; no open sub-tasks |
| 2 | **Test cases executed** | QA test run linked or "QA Approved" label set on ticket |
| 3 | **PR merged to base branch** | \`gh pr list --state merged --base <base>\` — PR for this story is in the list |
| 4 | **Code coverage ≥ 90%** | Last CI run passes coverage gate; confirm with last test report |
| 5 | **No linked P1/P2 bugs open** | No open critical/blocker issues linked to this story |
| 6 | **BA / PO demo approval** | Ticket has "Demo Approved" label or a BA/PO approval comment |
| 7 | **Documentation updated** | Changelog entry drafted; API docs / user guides updated if applicable |
| 8 | **Dependencies unblocked** | No upstream stories still open that this story depends on |
| 9 | **Rollback plan documented** | For data migrations or destructive changes: rollback steps are in ticket comments or a linked doc |

---

## 4. Handle Readiness Failures

If **any** story fails the gate, present the failure summary and ask:

> *"The following stories did not pass the readiness gate:*
> *— [#ID] [Title]: failed criteria [#N, #N]*
> *Options: (A) Exclude from release scope, (B) Block release until fixed, (C) Proceed with known risk (requires explicit approval). How would you like to proceed?"*

Only continue after receiving explicit direction. Record the decision in the release notes.

---

## 5. Build Changelog

Using only the **approved stories**, build the changelog grouped by type:

\`\`\`bash
git log --oneline <last-tag>..HEAD
\`\`\`

Structure:

\`\`\`markdown
## [<version>] — <date>

### Features
- (#ID) <story title>

### Bug Fixes
- (#ID) <bug title>

### Chores / Infrastructure
- (#ID) <chore title>
\`\`\`

Create or update \`CHANGELOG.md\`.

---

## 6. Smart-Deployment Analysis

Retrieve current org state and analyze metadata dependencies:

\`\`\`bash
sf profiler retrieve --target-org <staging-alias>
sf smart-deployment analyze --target-org <staging-alias>
\`\`\`

**Active Monitoring:** Wait for analysis to complete. Review the dependency graph for conflicts or ordering issues before proceeding.

---

## 7. Validate

\`\`\`bash
sf smart-deployment validate --target-org <staging-alias> --test-level RunLocalTests
\`\`\`

**Active Monitoring:** Poll until validation completes.
If validation **fails**, stop and report errors. Do not proceed to Step 8.

---

## 8. Bump Version and Tag

Only execute after Step 7 passes:

\`\`\`bash
npm version <major|minor|patch> --no-git-tag-version
git add package.json
git commit -m "chore(<ID>): bump version to <version>"
git tag -a v<version> -m "Release v<version>"
git push origin v<version>
\`\`\`

---

## 9. Deploy

\`\`\`bash
sf smart-deployment start --target-org <production-alias> --test-level RunAllTestsInOrg
\`\`\`

**Active Monitoring:** Monitor the deployment until it completes. Report status (pass/fail), duration, and any errors.

---

## 10. Post-Deploy Verification

1. Open the org and run smoke tests against the deployed stories:

\`\`\`bash
sf org open --target-org <production-alias>
\`\`\`

2. For each story in the release, confirm:
   - Feature is accessible to expected persona / Permission Set Group
   - No regressions in adjacent features

3. Update issue tracker:
   - Close stories with the deployed version tag
   - Set Fix Version / milestone to the released version

4. Announce the release (Slack / email / internal channel) with the changelog summary.
`),
        'ci-publish-agents.md': workflow(version, 'CI: Publish & Activate Agent Metadata (API 66)', `
## Overview

API 66 splits agent metadata into two separate deployment lanes:

| Lane | Source dir | Deploy command |
|------|-----------|----------------|
| Standard metadata (Apex, LWC, flows, etc.) | \`force-app/\` | \`sf project deploy start\` |
| Agent authoring bundles | \`aiAuthoringBundles/\` | \`sf agent publish authoring-bundle\` |
| Agent planner bundles (managed by Salesforce) | \`genAiPlannerBundles/\` | **do not deploy** — added to \`.forceignore\` |

Run this workflow after every merge to a release branch that touches \`aiAuthoringBundles/\`.

---

## 1. Guard: Verify API Version

\`\`\`bash
node -e "const p=require('./sfdx-project.json'); const v=parseFloat(p.sourceApiVersion||0); if(v<66){console.error('API',v,'< 66 — agent publish not supported'); process.exit(1);}"
\`\`\`

If it fails, update \`sfdx-project.json\` → \`sourceApiVersion\` to \`"66.0"\` before continuing.

---

## 2. Detect Changed Agent Bundles

Compare HEAD to the previous deployed SHA (\`PREV_SHA\` env var or last release tag):

\`\`\`bash
PREV_SHA=\${PREV_SHA:-$(git describe --tags --abbrev=0 2>/dev/null || git rev-list --max-parents=0 HEAD)}
CHANGED_BUNDLES=$(git diff --name-only "$PREV_SHA" HEAD -- 'aiAuthoringBundles/*' \\
  | sed 's|aiAuthoringBundles/||' | cut -d/ -f1 | sort -u)

if [ -z "$CHANGED_BUNDLES" ]; then
  echo "No agent bundles changed — skipping publish."
  exit 0
fi

echo "Bundles to publish: $CHANGED_BUNDLES"
\`\`\`

---

## 3. Publish Each Bundle

\`\`\`bash
for BUNDLE in $CHANGED_BUNDLES; do
  echo "Publishing: $BUNDLE"
  sf agent publish authoring-bundle \\
    --name "$BUNDLE" \\
    --skip-retrieve \\
    --concise \\
    --target-org "$TARGET_ORG"
done
\`\`\`

**Active Monitoring:** Wait for each publish to complete before proceeding to activation.

---

## 4. Activate Each Bundle

Retrieve the latest version number after publish:

\`\`\`bash
for BUNDLE in $CHANGED_BUNDLES; do
  VERSION=$(sf agent list versions --name "$BUNDLE" --target-org "$TARGET_ORG" --json \\
    | jq -r '.result | sort_by(.versionNumber) | last | .versionNumber')
  echo "Activating $BUNDLE v$VERSION"
  sf agent activate \\
    --name "$BUNDLE" \\
    --version "$VERSION" \\
    --target-org "$TARGET_ORG"
done
\`\`\`

---

## 5. Verify

\`\`\`bash
sf agent validate --target-org "$TARGET_ORG"
\`\`\`

Report: bundles published, versions activated, any errors.

---

## .forceignore Note

Ensure \`force-app/main/default/.forceignore\` (or root \`.forceignore\`) contains:

\`\`\`
# Managed by sf agent publish — never deploy via sf project deploy start
genAiPlannerBundles/
\`\`\`

This prevents the standard deploy lane from overwriting Salesforce-managed planner bundles.
`),
        'ci-publish-community.md': workflow(version, 'CI: Publish Experience Cloud Site (Idempotent)', `
## Overview

Experience Cloud sites live under \`digitalExperiences/site/<SiteName>/\`.
Use this workflow after any merge that changes site metadata.
The publish command is **idempotent** — running it on an unchanged site is a no-op.

---

## 1. Detect Changed Sites

\`\`\`bash
PREV_SHA=\${PREV_SHA:-$(git describe --tags --abbrev=0 2>/dev/null || git rev-list --max-parents=0 HEAD)}
CHANGED_SITES=$(git diff --name-only "$PREV_SHA" HEAD -- 'digitalExperiences/site/*' \\
  | sed 's|digitalExperiences/site/||' | cut -d/ -f1 | sort -u)

if [ -z "$CHANGED_SITES" ]; then
  echo "No Experience Cloud sites changed — skipping community publish."
  exit 0
fi

echo "Sites to publish: $CHANGED_SITES"
\`\`\`

---

## 2. Publish Each Site

\`\`\`bash
for SITE in $CHANGED_SITES; do
  echo "Publishing site: $SITE"
  sf community publish --name "$SITE" --target-org "$TARGET_ORG"
done
\`\`\`

**Active Monitoring:** Wait for each publish to complete. A typical publish takes 1–3 minutes.

---

## 3. Verify

After all publishes complete, open each site and confirm it loads:

\`\`\`bash
sf org open --target-org "$TARGET_ORG" --path "/s/"
\`\`\`

Report: sites published, any errors, confirmation that the live URL is accessible.

---

## Notes

- \`sf community publish\` does not require a version — it always publishes the current draft.
- Only the **affected site** is published; other sites are untouched.
- If the site name contains spaces, quote it: \`--name "My Portal"\`.
`),
        'ci-precheck-evals.md': workflow(version, 'CI: Evaluation Definition Precheck', `
## Overview

\`aiEvaluationDefinitions/\` XML files reference agent subjects via \`<subjectName>\`.
If a referenced subject does not exist in source or in the target org, the evaluation will
fail at deploy time with a cryptic error. This workflow runs **before** deploy to catch
broken references early.

---

## 1. Extract All Subject References

\`\`\`bash
SUBJECT_NAMES=$(grep -r '<subjectName>' aiEvaluationDefinitions/ 2>/dev/null \\
  | sed 's/.*<subjectName>//;s|</subjectName>.*||' | tr -d '[:space:]' | sort -u)

if [ -z "$SUBJECT_NAMES" ]; then
  echo "No aiEvaluationDefinitions found — precheck skipped."
  exit 0
fi

echo "Referenced subjects: $SUBJECT_NAMES"
\`\`\`

---

## 2. Check Existence in Source

\`\`\`bash
MISSING=()
for SUBJECT in $SUBJECT_NAMES; do
  # Check aiAuthoringBundles/ and force-app/ for any file matching the subject name
  FOUND=$(find aiAuthoringBundles force-app -name "\${SUBJECT}*" 2>/dev/null | head -1)
  if [ -z "$FOUND" ]; then
    MISSING+=("$SUBJECT")
  fi
done
\`\`\`

---

## 3. Check Existence in Org (if source check fails)

For subjects not found in source, query the org:

\`\`\`bash
for SUBJECT in "\${MISSING[@]}"; do
  ORG_RESULT=$(sf data query \\
    --query "SELECT Id FROM GenAiPlugin WHERE DeveloperName = '$SUBJECT' LIMIT 1" \\
    --target-org "$TARGET_ORG" --json 2>/dev/null | jq -r '.result.totalSize')
  if [ "$ORG_RESULT" = "0" ] || [ -z "$ORG_RESULT" ]; then
    echo "ERROR: subjectName '$SUBJECT' not found in source or org."
    HARD_MISSING+=("$SUBJECT")
  else
    echo "OK (org): $SUBJECT"
  fi
done
\`\`\`

---

## 4. Fail If Any Subject Is Missing

\`\`\`bash
if [ \${#HARD_MISSING[@]} -gt 0 ]; then
  echo ""
  echo "PRECHECK FAILED — broken subjectName references:"
  for S in "\${HARD_MISSING[@]}"; do
    echo "  - $S"
  done
  echo ""
  echo "Fix: ensure each aiEvaluationDefinitions/<file>.xml references a valid"
  echo "     aiAuthoringBundle or GenAiPlugin that exists in source or the target org."
  exit 1
fi

echo "All subjectName references valid — precheck passed."
\`\`\`

---

## Notes

- Run this step **before** \`sf project deploy validate\` in CI.
- A broken \`<subjectName>\` cannot be fixed after deploy — it must be corrected in source.
- This precheck is a no-op when \`aiEvaluationDefinitions/\` does not exist.
`),
        'create-scratch-org.md': workflow(version, 'Create and Setup Scratch Org', `
## 1. Confirm Definition File

Read \`config/project-scratch-def.json\` and confirm settings with the developer.

## 2. Create Scratch Org

\`\`\`bash
sf org create scratch --definition-file config/project-scratch-def.json --alias <alias> --duration-days 7
\`\`\`

## 3. Deploy Source

\`\`\`bash
sf project deploy start -d force-app --target-org <alias>
\`\`\`

**Active Monitoring:** Wait for the deployment to complete and report the result
before moving to the next step.

## 4. Assign Permission Sets

\`\`\`bash
sf org assign permset --name <PermSetName> --target-org <alias>
\`\`\`

## 5. Load Sample Data (if applicable)

\`\`\`bash
sf data import tree --plan data/sample-data-plan.json --target-org <alias>
\`\`\`

Report the scratch org URL:

\`\`\`bash
sf org open --target-org <alias>
\`\`\`
`),
    };
}
//# sourceMappingURL=devops.js.map