<template>
  <section class="psadt-workbench">
    <div class="page-header compact-header">
      <div>
        <span class="eyebrow">PSAPPDEPLOYTOOLKIT WORKBENCH</span>
        <h2>PSADT deployment factory</h2>
        <p>Build deployment profiles, generate Invoke-AppDeployToolkit scaffolds, and keep Intune-ready commands aligned with PSADT guidance.</p>
      </div>
      <div class="page-actions">
        <button class="ghost-button compact" type="button" @click="$emit('refresh')"><RefreshCw :size="16" />Refresh</button>
        <button class="primary-action compact" type="button" @click="openProfileModal()"><PackagePlus :size="16" />New PSADT profile</button>
      </div>
    </div>

    <div class="psadt-summary-grid">
      <article class="glass-panel psadt-kpi"><BookOpenText :size="20" /><strong>{{ catalog.supportMatrix?.length || 0 }}</strong><span>supported areas</span></article>
      <article class="glass-panel psadt-kpi"><PackageCheck :size="20" /><strong>{{ profiles.length }}</strong><span>deployment profiles</span></article>
      <article class="glass-panel psadt-kpi"><TerminalSquare :size="20" /><strong>{{ catalog.module?.moduleVersion || '4.x' }}</strong><span>upstream module</span></article>
      <article class="glass-panel psadt-kpi"><Puzzle :size="20" /><strong>{{ catalog.functions?.length || 0 }}</strong><span>public functions</span></article>
    </div>

    <article class="glass-panel psadt-panel intune-publisher-panel">
      <div class="section-title">
        <div>
          <h3>Intune Publishing Wizard</h3>
          <p>Prepare, validate, and track PSADT Win32 app publishing from package source through assignments.</p>
        </div>
        <button class="primary-action compact" type="button" @click="openIntuneDeploymentModal()"><CloudCog :size="15" />New publishing plan</button>
      </div>

      <div class="publisher-shell">
        <aside class="publisher-steps">
          <button
            v-for="(step, index) in publishingSteps"
            :key="step.id"
            :class="{ active: activePublishStep === index, complete: stepComplete(step.id) }"
            type="button"
            @click="activePublishStep = index"
          >
            <span>{{ index + 1 }}</span>
            <strong>{{ step.title }}</strong>
            <small>{{ step.summary }}</small>
          </button>
        </aside>

        <section class="publisher-stage">
          <header>
            <span class="eyebrow">STEP {{ activePublishStep + 1 }} OF {{ publishingSteps.length }}</span>
            <h4>{{ currentPublishingStep.title }}</h4>
            <p>{{ currentPublishingStep.summary }}</p>
          </header>

          <div class="publisher-stage-grid">
            <div class="publisher-card">
              <strong>Current plan</strong>
              <label>
                <span>Deployment plan</span>
                <select v-model="selectedIntuneDeploymentId">
                  <option value="">Draft from defaults</option>
                  <option v-for="deployment in intuneDeployments" :key="deployment.id" :value="deployment.id">{{ deployment.name }}</option>
                </select>
              </label>
              <dl>
                <div><dt>Command style</dt><dd>{{ currentDeployment.commandStyle === 'legacy-v3' ? 'Legacy v3' : 'PSADT v4' }}</dd></div>
                <div><dt>Install behavior</dt><dd>{{ currentDeployment.installBehavior }}</dd></div>
                <div><dt>UI mode</dt><dd>{{ currentDeployment.uiMode }}</dd></div>
                <div><dt>Restart</dt><dd>{{ currentDeployment.restartBehavior }}</dd></div>
              </dl>
              <button class="ghost-button compact" type="button" @click="openIntuneDeploymentModal(selectedIntuneDeployment || null)">Edit plan</button>
            </div>

            <div class="publisher-card publisher-guidance">
              <strong>{{ currentPublishingStep.title }} checklist</strong>
              <div v-if="currentPublishingStep.id === 'source'">
                <span v-for="row in sourceChecklist" :key="row" class="check-row">{{ row }}</span>
              </div>
              <div v-else-if="currentPublishingStep.id === 'commands'">
                <code>{{ currentDeployment.installCommand || recommendedCommands.install }}</code>
                <code>{{ currentDeployment.uninstallCommand || recommendedCommands.uninstall }}</code>
              </div>
              <div v-else-if="currentPublishingStep.id === 'requirements'">
                <span class="check-row">Architecture: {{ currentDeployment.requirements?.architecture || 'x64' }}</span>
                <span class="check-row">Minimum OS: {{ currentDeployment.requirements?.minOs || 'Windows 10 22H2' }}</span>
                <span class="check-row">Run as 32-bit: {{ currentDeployment.requirements?.runAs32Bit ? 'yes' : 'no' }}</span>
              </div>
              <div v-else-if="currentPublishingStep.id === 'detection'">
                <span class="check-row">{{ currentDeployment.detectionType }}</span>
                <p>{{ currentDeployment.detectionRule || 'Add a detection rule before marking the plan ready.' }}</p>
              </div>
              <div v-else-if="currentPublishingStep.id === 'returns'">
                <span v-for="row in currentDeployment.returnCodes" :key="`${row.code}-${row.type}`" class="check-row">{{ row.code }} - {{ row.type }} - {{ row.meaning }}</span>
              </div>
              <div v-else-if="currentPublishingStep.id === 'assignments'">
                <span v-for="row in currentDeployment.assignments" :key="`${row.ring}-${row.intent}`" class="check-row">{{ row.ring }} - {{ row.intent }} - {{ row.groupName || 'group pending' }}</span>
              </div>
              <div v-else>
                <span v-for="finding in compatibilityFindings" :key="finding.id" :class="['check-row', finding.level]">{{ finding.text }}</span>
              </div>
            </div>

            <div class="publisher-score">
              <span class="eyebrow">COMPATIBILITY</span>
              <strong>{{ compatibilityScore }}</strong>
              <p>{{ compatibilityScore >= 90 ? 'Ready for Intune publish review.' : 'Complete the highlighted plan fields before publishing.' }}</p>
              <div>
                <span v-for="finding in compatibilityFindings.slice(0, 4)" :key="finding.id" :class="['status-pill', finding.level]">{{ finding.label }}</span>
              </div>
            </div>
          </div>

          <footer class="publisher-actions">
            <button class="ghost-button compact" type="button" :disabled="activePublishStep === 0" @click="activePublishStep -= 1">Previous</button>
            <button class="ghost-button compact" type="button" :disabled="activePublishStep === publishingSteps.length - 1" @click="activePublishStep += 1">Next</button>
            <button class="primary-action compact" type="button" @click="openIntuneDeploymentModal(selectedIntuneDeployment || null)">Configure step</button>
          </footer>
        </section>
      </div>
    </article>

    <article class="glass-panel psadt-panel psadt-verifier-panel">
      <div class="section-title"><h3>Best Practice Verifier</h3><ClipboardCheck :size="18" /></div>
      <div class="psadt-verifier-grid">
        <div class="psadt-verifier-controls">
          <label>
            <span>Target</span>
            <select v-model="validationTarget">
              <option value="script">Saved script</option>
              <option value="profile">Rendered PSADT profile</option>
              <option value="raw">Raw content</option>
            </select>
          </label>
          <label v-if="validationTarget === 'script'">
            <span>Script</span>
            <select v-model="validationScriptId">
              <option value="">Choose script</option>
              <option v-for="script in scripts" :key="script.id" :value="script.id">{{ script.name }}</option>
            </select>
          </label>
          <label v-if="validationTarget === 'profile'">
            <span>Profile</span>
            <select v-model="validationProfileId">
              <option value="">Choose profile</option>
              <option v-for="profile in profiles" :key="profile.id" :value="profile.id">{{ profile.name }}</option>
            </select>
          </label>
          <label>
            <span>Platform context</span>
            <select v-model="validationPlatform">
              <option value="intune">Intune</option>
              <option value="configmgr">Configuration Manager</option>
              <option value="gpo">Group Policy</option>
              <option value="manual">Manual</option>
            </select>
          </label>
          <textarea v-if="validationTarget === 'raw'" v-model="validationRaw" placeholder="Paste Invoke-AppDeployToolkit.ps1 content..." rows="7"></textarea>
          <button class="primary-action compact" type="button" :disabled="!canValidate" @click="runValidation">
            <ClipboardCheck :size="15" />Run verifier
          </button>
        </div>
        <div class="psadt-verifier-score">
          <div>
            <span class="eyebrow">READINESS SCORE</span>
            <strong>{{ validationResult?.score ?? '-' }}</strong>
            <p>{{ validationResult?.ok ? 'No blocking PSADT findings.' : 'Review critical/error findings before deployment.' }}</p>
          </div>
          <div class="verifier-counts">
            <span><strong>{{ validationResult?.counts?.critical || 0 }}</strong>critical</span>
            <span><strong>{{ validationResult?.counts?.error || 0 }}</strong>errors</span>
            <span><strong>{{ validationResult?.counts?.warning || 0 }}</strong>warnings</span>
            <span><strong>{{ validationResult?.counts?.info || 0 }}</strong>info</span>
          </div>
        </div>
      </div>

      <div class="mini-table-wrap verifier-table-wrap">
        <table class="mini-table verifier-table">
          <thead><tr><th>Severity</th><th>Rule</th><th>Line</th><th>Finding</th><th>Remediation</th></tr></thead>
          <tbody>
            <tr v-for="finding in validationResult?.findings || []" :key="finding.id">
              <td><span :class="['status-pill', finding.severity]">{{ finding.severity }}</span></td>
              <td><strong>{{ finding.ruleId }}</strong><small>{{ finding.category }}</small></td>
              <td>{{ finding.line || '-' }}</td>
              <td><strong>{{ finding.title }}</strong><small>{{ finding.excerpt }}</small></td>
              <td>{{ finding.remediation }}</td>
            </tr>
          </tbody>
        </table>
        <div v-if="validationResult && !validationResult.findings?.length" class="widget-empty">No PSADT verifier findings for this target.</div>
        <div v-if="!validationResult" class="widget-empty">Run the verifier against a script, profile, or pasted content.</div>
      </div>
    </article>

    <article class="glass-panel psadt-panel psadt-migration-panel">
      <div class="section-title"><h3>Migration Wizard</h3><WandSparkles :size="18" /></div>
      <div class="psadt-verifier-grid">
        <div class="psadt-verifier-controls">
          <label>
            <span>Source</span>
            <select v-model="migrationTarget">
              <option value="script">Saved script</option>
              <option value="raw">Raw content</option>
            </select>
          </label>
          <label v-if="migrationTarget === 'script'">
            <span>Script</span>
            <select v-model="migrationScriptId">
              <option value="">Choose script</option>
              <option v-for="script in scripts" :key="script.id" :value="script.id">{{ script.name }}</option>
            </select>
          </label>
          <label>
            <span>Target</span>
            <select v-model="migrationTargetVersion"><option value="4.2.0">PSADT 4.2.0</option></select>
          </label>
          <textarea v-if="migrationTarget === 'raw'" v-model="migrationRaw" placeholder="Paste legacy Deploy-Application.ps1 content..." rows="7"></textarea>
          <button class="ghost-button compact" type="button" :disabled="!canPlanMigration" @click="planMigration">
            <ListChecks :size="15" />Plan
          </button>
          <button class="primary-action compact" type="button" :disabled="!migrationPlanResult" @click="applyMigration">
            <FilePlus2 :size="15" />Create migrated copy
          </button>
        </div>
        <div class="psadt-verifier-score">
          <div>
            <span class="eyebrow">MIGRATION PLAN</span>
            <strong>{{ migrationPlanResult?.summary?.steps ?? '-' }}</strong>
            <p>{{ migrationPlanResult ? `${migrationPlanResult.summary.replacements} automatic replacements, ${migrationPlanResult.summary.manual} manual review items.` : 'Run a plan against a legacy script.' }}</p>
          </div>
          <div class="verifier-counts">
            <span><strong>{{ migrationPlanResult?.summary?.automatic || 0 }}</strong>auto steps</span>
            <span><strong>{{ migrationPlanResult?.summary?.manual || 0 }}</strong>manual</span>
            <span><strong>{{ migrationPlanResult?.targetVersion || '4.2.0' }}</strong>target</span>
            <span><strong>{{ migrationPlanResult?.migratedScript ? 'yes' : 'no' }}</strong>created</span>
          </div>
        </div>
      </div>
      <div class="mini-table-wrap verifier-table-wrap">
        <table class="mini-table verifier-table">
          <thead><tr><th>Mode</th><th>Step</th><th>Lines</th><th>Status</th><th>Guidance</th></tr></thead>
          <tbody>
            <tr v-for="step in migrationPlanResult?.steps || []" :key="step.id">
              <td><span :class="['status-pill', step.automatic ? 'completed' : 'warning']">{{ step.automatic ? 'auto' : 'review' }}</span></td>
              <td><strong>{{ step.id }}</strong><small>{{ step.title }}</small></td>
              <td>{{ step.lines?.join(', ') || '-' }}</td>
              <td>{{ step.status }}</td>
              <td>{{ step.guidance || step.replacement || '-' }}</td>
            </tr>
          </tbody>
        </table>
        <div v-if="!migrationPlanResult" class="widget-empty">Plan a migration to preview automatic replacements and manual review items.</div>
      </div>
    </article>

    <article class="glass-panel psadt-panel psadt-intune-panel">
      <div class="section-title">
        <h3>Intune Deployment Coverage</h3>
        <button class="primary-action compact" type="button" @click="openIntuneDeploymentModal()"><CloudCog :size="15" />New deployment plan</button>
      </div>
      <div class="intune-coverage-grid">
        <section>
          <strong>Packaging</strong>
          <div v-for="row in catalog.intune?.packaging || []" :key="row.area"><code>{{ row.area }}</code><span>{{ row.guidance }}</span></div>
        </section>
        <section>
          <strong>Return codes</strong>
          <div v-for="row in catalog.intune?.returnCodes || []" :key="row.code"><code>{{ row.code }}</code><span>{{ row.type }} - {{ row.meaning }}</span></div>
        </section>
        <section>
          <strong>Detection rules</strong>
          <div v-for="row in catalog.intune?.detectionRules || []" :key="row.type"><code>{{ row.type }}</code><span>{{ row.bestFor }} - {{ row.notes }}</span></div>
        </section>
        <section>
          <strong>Management actions</strong>
          <div v-for="row in catalog.intune?.managementActions || []" :key="row.action"><code>{{ row.action }}</code><span>{{ row.apiStatus }} - {{ row.guidance }}</span></div>
        </section>
      </div>
      <div class="intune-gotchas">
        <span v-for="item in catalog.intune?.gotchas || []" :key="item">{{ item }}</span>
      </div>
    </article>

    <article class="glass-panel psadt-panel app-catalog-panel">
      <div class="section-title">
        <div>
          <h3>Application Catalog</h3>
          <p>Group versioned deployments per application and track upstream version updates. Adopt existing tenant apps as a migration aid.</p>
        </div>
        <div class="table-actions">
          <button class="ghost-button compact" type="button" @click="openImportModal"><PackagePlus :size="15" />Import from tenant</button>
          <button class="primary-action compact" type="button" @click="openApplicationModal()"><PackageCheck :size="15" />New application</button>
        </div>
      </div>
      <div class="mini-table-wrap">
        <table class="mini-table">
          <thead><tr><th>Application</th><th>Current</th><th>Upstream</th><th>Update</th><th>Source</th><th>Deployments</th><th>Actions</th></tr></thead>
          <tbody>
            <tr v-for="app in applications" :key="app.id">
              <td><strong>{{ app.name }}</strong><small>{{ app.vendor || app.publisher || '-' }}</small></td>
              <td><code>{{ app.currentVersion || '-' }}</code></td>
              <td><code>{{ app.latestKnownVersion || '-' }}</code></td>
              <td>
                <span v-if="app.updateState?.updateAvailable" class="status-pill warning">update available</span>
                <span v-else class="status-pill completed">up to date</span>
              </td>
              <td>{{ app.versionSource }}</td>
              <td>{{ app.deploymentCount }}</td>
              <td>
                <div class="table-actions">
                  <button class="ghost-button compact" type="button" @click="openApplicationModal(app)">Edit</button>
                  <button class="ghost-button compact" type="button" @click="$emit('check-application-update', app.id)"><RefreshCw :size="13" />Check</button>
                </div>
              </td>
            </tr>
          </tbody>
        </table>
        <div v-if="!applications.length" class="widget-empty">No catalog applications yet. Create one or import from your tenant.</div>
      </div>
    </article>

    <article class="glass-panel psadt-panel governance-panel">
      <div class="section-title">
        <div>
          <h3>Governance &amp; Reporting</h3>
          <p>Approve tenant-changing requests and review rollout health across visible deployments.</p>
        </div>
        <button class="ghost-button compact" type="button" @click="$emit('refresh-governance')"><RefreshCw :size="15" />Refresh</button>
      </div>
      <div class="graph-tracking-grid">
        <section class="publisher-card">
          <strong>Pending approvals</strong>
          <div v-for="request in pendingChangeRequests" :key="request.id" class="check-row">
            <b>{{ request.deploymentName || request.deploymentId }} · {{ request.action }}</b>
            <small>by {{ request.requesterEmail || 'unknown' }} · {{ request.createdAt }}</small>
            <div class="publisher-actions">
              <button class="primary-action compact" type="button" @click="$emit('approve-change-request', request.id)">Approve</button>
              <button class="ghost-button compact danger-text" type="button" @click="$emit('reject-change-request', request.id)">Reject</button>
            </div>
          </div>
          <p v-if="!pendingChangeRequests.length" class="widget-empty">No pending change requests.</p>
        </section>

        <section class="publisher-card">
          <strong>Deployments by status</strong>
          <div v-for="row in reportingOverview?.deploymentsByStatus || []" :key="row.status" class="check-row">
            <b>{{ row.status }}</b><small>{{ row.count }}</small>
          </div>
          <p v-if="!reportingOverview?.deploymentsByStatus?.length" class="widget-empty">No deployment data.</p>
        </section>

        <section class="publisher-card">
          <strong>Install health &amp; top errors</strong>
          <div v-for="row in reportingOverview?.installStateCounts || []" :key="row.state" class="check-row">
            <b>{{ row.state }}</b><small>{{ row.count }}</small>
          </div>
          <div v-for="row in reportingOverview?.topErrors || []" :key="row.code" class="check-row">
            <b><code>{{ row.code }}</code></b><small>{{ row.count }} failure(s)</small>
          </div>
          <p v-if="!reportingOverview?.installStateCounts?.length" class="widget-empty">No synced install status yet.</p>
        </section>

        <section class="publisher-card">
          <strong>Soak / SLA timers</strong>
          <div v-for="row in reportingOverview?.soakTimers || []" :key="row.id" class="check-row">
            <b>{{ row.name }} → {{ row.ring }}</b>
            <small :class="row.hoursRemaining <= 0 ? 'danger-text' : ''">{{ row.hoursRemaining <= 0 ? 'promotion due' : `${row.hoursRemaining}h remaining` }}</small>
          </div>
          <p v-if="!reportingOverview?.soakTimers?.length" class="widget-empty">No deployments in soak.</p>
        </section>

        <section class="publisher-card">
          <strong>Write activity (14 days)</strong>
          <div v-for="row in reportingOverview?.auditTrend || []" :key="`${row.day}-${row.status}`" class="check-row">
            <b>{{ row.day }}</b><small><span :class="['status-pill', row.status === 'success' ? 'completed' : 'critical']">{{ row.status }}</span> {{ row.count }}</small>
          </div>
          <p v-if="!reportingOverview?.auditTrend?.length" class="widget-empty">No tenant write activity yet.</p>
        </section>
      </div>
    </article>

    <ResourceTable
      :columns="intuneColumns"
      :rows="filteredIntuneDeployments"
      :total="filteredIntuneDeployments.length"
      :search="intuneSearch"
      :page="1"
      :page-count="1"
      :page-size="20"
      search-placeholder="Search Intune deployment plans..."
      item-label="deployment plans"
      empty-text="No Intune deployment plans have been created yet."
      @update:search="intuneSearch = $event"
      @sort="noop"
    >
      <template #cell-name="{ row }"><strong>{{ row.name }}</strong></template>
      <template #cell-profile="{ row }">{{ row.profileName || row.scriptName || 'Manual commands' }}</template>
      <template #cell-status="{ row }"><span :class="['status-pill', row.status]">{{ row.status }}</span></template>
      <template #cell-package="{ row }"><code>{{ row.intunewinFile || row.sourceFolder || 'package pending' }}</code></template>
      <template #cell-assignments="{ row }">{{ row.assignments?.map((item) => item.ring).join(', ') || '-' }}</template>
      <template #cell-actions="{ row }">
        <div class="table-actions">
          <button class="ghost-button compact" type="button" @click="openIntuneDeploymentModal(row)">Edit</button>
          <button class="ghost-button compact" type="button" @click="$emit('new-version', row.id)"><PackagePlus :size="13" />New version</button>
          <button class="ghost-button compact danger-text" type="button" @click="$emit('delete-intune-deployment', row.id)">Delete</button>
        </div>
      </template>
    </ResourceTable>

    <article class="glass-panel psadt-panel graph-tracking-panel">
      <div class="section-title">
        <div>
          <h3>Microsoft Graph Intune Tracking</h3>
          <p>Use Config / Intune Graph environments to link mobile app IDs, sync install reports, and inspect device/user failures.</p>
        </div>
      </div>

      <div class="graph-tracking-grid">
        <section class="publisher-card">
          <strong>Tracking target</strong>
          <label>
            <span>Deployment plan</span>
            <select v-model="graphDeploymentId" @change="hydrateGraphTarget">
              <option value="">Choose deployment</option>
              <option v-for="deployment in intuneDeployments" :key="deployment.id" :value="deployment.id">{{ deployment.name }}</option>
            </select>
          </label>
          <label>
            <span>Graph environment</span>
            <select v-model="graphConnectionId">
              <option value="">Choose environment</option>
              <option v-for="connection in graphConnections" :key="connection.id" :value="connection.id">{{ connection.name }}</option>
            </select>
          </label>
          <label>
            <span>Intune mobile app id</span>
            <input v-model="graphAppId" placeholder="Graph mobileApp id" />
          </label>
          <div class="publisher-actions">
            <button class="ghost-button compact" type="button" :disabled="!canLinkGraph" @click="linkGraphApp"><Link2 :size="14" />Link</button>
            <button class="primary-action compact" type="button" :disabled="!canLinkGraph" @click="syncGraphStatus"><RefreshCw :size="14" />Sync status</button>
            <button class="ghost-button compact" type="button" :disabled="!graphDeploymentId" @click="$emit('load-graph-status', graphDeploymentId)">View stored</button>
          </div>
        </section>

        <section class="publisher-card">
          <strong>Tenant write-back</strong>
          <p v-if="!selectedWriteConnection" class="widget-empty">Choose a deployment and Graph environment above to publish.</p>
          <p v-else-if="!selectedWriteConnection.allowWrite" class="widget-empty">This environment is read-only. An admin must enable "Allow tenant write-back" in Config / Intune.</p>
          <template v-else>
            <span class="check-row"><b>{{ selectedWriteConnection.name }}</b><small>write-enabled · {{ graphAppId ? 'app linked' : 'not yet published' }}</small></span>
            <label>
              <span>Build .intunewin — setup file</span>
              <input v-model="buildSetupFile" :placeholder="builderStatus?.available ? 'setup.exe (relative to source folder)' : 'Build unavailable on this host'" :disabled="!builderStatus?.available" />
            </label>
            <div class="publisher-actions">
              <button class="ghost-button compact" type="button" :disabled="!builderStatus?.available || !buildSetupFile || !graphDeploymentId" @click="buildIntunewin"><PackagePlus :size="14" />Build package</button>
              <small v-if="builderStatus && !builderStatus.available" class="field-hint">{{ builderStatus.reason }}</small>
            </div>
            <label>
              <span>.intunewin content asset</span>
              <select v-model="contentAssetId">
                <option value="">Choose a package asset</option>
                <option v-for="asset in intunewinAssets" :key="asset.id" :value="asset.id">{{ asset.name }}</option>
              </select>
            </label>
            <div class="publisher-actions">
              <button class="primary-action compact" type="button" @click="publishGraphApp"><CloudCog :size="14" />Publish app</button>
              <button class="ghost-button compact" type="button" :disabled="!graphAppId || !contentAssetId" @click="uploadGraphContent"><PackagePlus :size="14" />Upload content</button>
            </div>
            <div class="publisher-actions">
              <button class="ghost-button compact" type="button" :disabled="!graphAppId" @click="assignGraphApp"><ListChecks :size="14" />Assign</button>
              <button class="ghost-button compact" type="button" :disabled="!graphAppId" @click="setGraphRelationships"><Puzzle :size="14" />Set relationships</button>
            </div>
            <div class="publisher-actions">
              <button class="ghost-button compact" type="button" :disabled="!graphAppId" @click="checkDrift"><SlidersHorizontal :size="14" />Check drift</button>
              <button class="ghost-button compact" type="button" :disabled="!graphAppId" @click="reconcileGraphApp"><RefreshCw :size="14" />Reconcile</button>
              <button class="ghost-button compact" type="button" :disabled="!graphDeploymentId" @click="$emit('load-graph-audit', graphDeploymentId)">Audit</button>
            </div>
            <div v-if="driftResult" class="drift-summary">
              <span v-if="driftResult.inSync" class="status-pill completed">in sync with tenant</span>
              <template v-else>
                <span class="status-pill warning">drift detected</span>
                <small v-for="d in driftResult.appDrift" :key="d.field">{{ d.field }}: plan "{{ d.expected }}" vs tenant "{{ d.actual }}"</small>
                <small v-if="driftResult.assignmentDrift.missing.length">{{ driftResult.assignmentDrift.missing.length }} assignment(s) missing in tenant</small>
                <small v-if="driftResult.assignmentDrift.extra.length">{{ driftResult.assignmentDrift.extra.length }} extra assignment(s) in tenant</small>
                <small v-if="driftResult.relationshipDrift.missing.length">{{ driftResult.relationshipDrift.missing.length }} relationship(s) missing in tenant</small>
              </template>
            </div>
          </template>
        </section>

        <section class="publisher-score">
          <span class="eyebrow">FAILURES</span>
          <strong>{{ graphStatusResult?.summary?.failed || 0 }}</strong>
          <p>{{ graphStatusResult ? `${graphStatusResult.summary.installed || 0} installed, ${graphStatusResult.summary.pending || 0} pending, ${graphStatusResult.summary.total || 0} total rows.` : 'Sync or load a deployment to view Intune status.' }}</p>
          <div>
            <span class="status-pill completed">{{ graphStatusResult?.summary?.devices || 0 }} devices</span>
            <span class="status-pill info">{{ graphStatusResult?.summary?.users || 0 }} users</span>
            <span class="status-pill warning">{{ graphStatusResult?.syncRuns?.[0]?.status || 'not synced' }}</span>
          </div>
        </section>

        <section class="publisher-card graph-connections-list">
          <strong>Configured environments</strong>
          <div v-for="connection in graphConnections" :key="connection.id" class="check-row">
            <b>{{ connection.name }}</b>
            <small>{{ connection.cloud }} - {{ connection.tenantId }} - {{ connection.lastTestStatus || 'untested' }}</small>
          </div>
          <p v-if="!graphConnections.length" class="widget-empty">No Microsoft Graph environments configured. Add them in Config / Intune.</p>
        </section>
      </div>

      <div v-if="selectedGraphDeployment?.relationships?.length" class="relationship-map">
        <span class="eyebrow">RELATIONSHIP MAP</span>
        <RelationshipGraph :deployment="selectedGraphDeployment" />
      </div>

      <div class="mini-table-wrap verifier-table-wrap">
        <table class="mini-table verifier-table">
          <thead><tr><th>State</th><th>Target</th><th>User</th><th>Device</th><th>Error</th><th>Cause</th><th>Last sync</th></tr></thead>
          <tbody>
            <tr v-for="row in graphStatusResult?.statuses || []" :key="row.id">
              <td><span :class="['status-pill', graphStatusClass(row.installState)]">{{ row.installState }}</span></td>
              <td>{{ row.scope }}</td>
              <td>{{ row.userPrincipalName || row.principalName || '-' }}</td>
              <td>{{ row.deviceName || row.deviceId || '-' }}</td>
              <td><code>{{ row.errorCode || '-' }}</code></td>
              <td>{{ row.errorDescription || row.installStateDetail || '-' }}</td>
              <td>{{ row.lastSyncDateTime || row.updatedAt }}</td>
            </tr>
          </tbody>
        </table>
        <div v-if="!graphStatusResult?.statuses?.length" class="widget-empty">No synced Intune status rows for this deployment yet.</div>
      </div>

      <div v-if="graphAuditResult?.length" class="mini-table-wrap verifier-table-wrap">
        <strong class="audit-heading">Tenant write-back audit</strong>
        <table class="mini-table verifier-table">
          <thead><tr><th>When</th><th>Action</th><th>Status</th><th>Actor</th><th>Graph app</th><th>Detail</th></tr></thead>
          <tbody>
            <tr v-for="entry in graphAuditResult" :key="entry.id">
              <td>{{ entry.createdAt }}</td>
              <td><code>{{ entry.action }}</code></td>
              <td><span :class="['status-pill', entry.status === 'success' ? 'completed' : 'critical']">{{ entry.status }}</span></td>
              <td>{{ entry.actorEmail || '-' }}</td>
              <td><code>{{ entry.targetGraphId || '-' }}</code></td>
              <td>{{ entry.message || '-' }}</td>
            </tr>
          </tbody>
        </table>
      </div>
    </article>

    <ResourceTable
      :columns="profileColumns"
      :rows="filteredProfiles"
      :total="filteredProfiles.length"
      :search="profileSearch"
      :page="1"
      :page-count="1"
      :page-size="20"
      search-placeholder="Search PSADT profiles..."
      item-label="profiles"
      empty-text="No PSADT deployment profiles have been created yet."
      @update:search="profileSearch = $event"
      @sort="noop"
    >
      <template #cell-name="{ row }"><strong>{{ row.name }}</strong></template>
      <template #cell-app="{ row }">{{ row.zeroConfig ? 'Zero-config MSI' : `${row.appVendor || '-'} ${row.appName || ''}` }}</template>
      <template #cell-mode="{ row }">{{ row.deploymentType }} / {{ row.deployMode }}</template>
      <template #cell-flags="{ row }">
        <span class="status-pill">{{ row.requireAdmin ? 'admin' : 'user' }}</span>
        <span v-if="row.zeroConfig" class="status-pill shared">zero-config</span>
      </template>
      <template #cell-actions="{ row }">
        <div class="table-actions">
          <button class="ghost-button compact" type="button" @click="openProfileModal(row)">Edit</button>
          <button class="ghost-button compact" type="button" @click="$emit('render-profile', row.id)">Preview</button>
          <button class="primary-action compact" type="button" @click="$emit('create-script', row.id)"><FilePlus2 :size="14" />Create script</button>
        </div>
      </template>
    </ResourceTable>

    <div class="psadt-grid">
      <article class="glass-panel psadt-panel psadt-support-panel">
        <div class="section-title"><h3>Support Matrix</h3><ShieldCheck :size="18" /></div>
        <div class="mini-table-wrap">
          <table class="mini-table">
            <thead><tr><th>Area</th><th>Mode</th><th>Status</th><th>Implementation</th></tr></thead>
            <tbody>
              <tr v-for="row in catalog.supportMatrix || []" :key="row.area">
                <td><strong>{{ row.area }}</strong><small>{{ sourceTitle(row.sourceId) }}</small></td>
                <td>{{ row.support }}</td>
                <td><span class="status-pill completed">{{ row.status }}</span></td>
                <td>{{ row.implementation }}</td>
              </tr>
            </tbody>
          </table>
        </div>
      </article>

      <article class="glass-panel psadt-panel">
        <div class="section-title"><h3>Deployment Structure</h3><FolderTree :size="18" /></div>
        <div class="psadt-structure-list">
          <div v-for="row in catalog.structure || []" :key="row.path">
            <code>{{ row.path }}</code>
            <span>{{ row.purpose }}</span>
            <strong>{{ row.required ? 'required' : 'optional' }}</strong>
          </div>
        </div>
      </article>

      <article class="glass-panel psadt-panel">
        <div class="section-title"><h3>Invoke Options</h3><TerminalSquare :size="18" /></div>
        <div class="psadt-option-list">
          <div v-for="param in catalog.invokeParameters || []" :key="param.name">
            <code>{{ param.name }}</code>
            <span>{{ param.values?.join(' / ') }}</span>
            <p>{{ param.description }}</p>
          </div>
        </div>
      </article>

      <article class="glass-panel psadt-panel psadt-function-panel">
        <div class="section-title"><h3>Public Function Coverage</h3><Braces :size="18" /></div>
        <div class="psadt-function-summary">
          <span v-for="row in functionCategoryCounts" :key="row.category"><strong>{{ row.count }}</strong>{{ row.category }}</span>
        </div>
        <div class="psadt-function-list">
          <button v-for="fn in catalog.functions || []" :key="fn.name" type="button" @click="$emit('insert-snippet', fn.snippet)">
            <code>{{ fn.name }}</code>
            <span>{{ fn.category }}</span>
          </button>
        </div>
      </article>

      <article class="glass-panel psadt-panel">
        <div class="section-title"><h3>ADMX Policy Surface</h3><SlidersHorizontal :size="18" /></div>
        <div class="psadt-option-list psadt-admx-list">
          <div v-for="policy in catalog.admxPolicies || []" :key="policy.name">
            <code>{{ policy.name }}</code>
            <span>{{ policy.category }}</span>
            <p>{{ policy.key }}</p>
          </div>
        </div>
      </article>

      <article class="glass-panel psadt-panel">
        <div class="section-title"><h3>Launch Commands</h3><TerminalSquare :size="18" /></div>
        <div class="psadt-option-list">
          <div v-for="command in catalog.launchCommands || []" :key="command.name">
            <code>{{ command.name }}</code>
            <p>{{ command.command }}</p>
          </div>
        </div>
      </article>
    </div>

    <BaseModal
      :open="graphModalOpen"
      :title="graphForm.id ? 'Update Graph environment' : 'New Graph environment'"
      eyebrow="MICROSOFT GRAPH"
      description="Store an Entra app registration used to read Intune app metadata and deployment status reports."
      wide
      @close="graphModalOpen = false"
    >
      <form class="form-grid" @submit.prevent="saveGraphConnection">
        <label><span>Name</span><input v-model="graphForm.name" required placeholder="Production Intune" /></label>
        <label><span>Cloud</span><select v-model="graphForm.cloud" @change="applyGraphCloudDefaults"><option value="global">Global</option><option value="gcc">GCC</option><option value="gcchigh">GCC High</option><option value="dod">DoD</option><option value="china">China</option><option value="custom">Custom</option></select></label>
        <label><span>Tenant ID</span><input v-model="graphForm.tenantId" required placeholder="tenant-guid-or-domain" /></label>
        <label><span>Client ID</span><input v-model="graphForm.clientId" required placeholder="app-registration-client-id" /></label>
        <label class="full"><span>Client secret</span><input v-model="graphForm.clientSecret" :required="!graphForm.id" type="password" placeholder="Stored encrypted; leave blank to keep existing secret" /></label>
        <label><span>Graph base URL</span><input v-model="graphForm.graphBaseUrl" required /></label>
        <label><span>Authority host</span><input v-model="graphForm.authorityHost" required /></label>
        <label><span>Default API version</span><select v-model="graphForm.defaultApiVersion"><option value="v1.0">v1.0</option><option value="beta">beta</option></select></label>
        <label><span>Visibility</span><select v-model="graphForm.visibility"><option value="personal">Personal</option><option value="shared">Shared</option><option value="group">Group</option></select></label>
        <label v-if="graphForm.visibility === 'group'"><span>Group</span><select v-model="graphForm.groupId"><option value="">Choose group</option><option v-for="group in groups" :key="group.id" :value="group.id">{{ group.name }}</option></select></label>
        <label class="toggle modal-toggle"><input v-model="graphForm.enabled" type="checkbox" /><span><strong>Enabled</strong><small>Allow this environment to be used for Graph sync.</small></span></label>
        <div class="form-actions modal-actions full">
          <button class="ghost-button" type="button" @click="graphModalOpen = false">Cancel</button>
          <button v-if="graphForm.id" class="ghost-button danger-text" type="button" @click="deleteGraphConnection">Delete</button>
          <button class="primary-action" type="submit"><Save :size="17" />Save environment</button>
        </div>
      </form>
    </BaseModal>

    <BaseModal
      :open="applicationModalOpen"
      :title="applicationForm.id ? 'Update application' : 'New application'"
      eyebrow="APPLICATION CATALOG"
      description="Group versioned deployments under one application and track the upstream version."
      wide
      @close="applicationModalOpen = false"
    >
      <form class="form-grid" @submit.prevent="saveApplication">
        <label><span>Name</span><input v-model="applicationForm.name" required placeholder="Microsoft Edge" /></label>
        <label><span>Vendor</span><input v-model="applicationForm.vendor" placeholder="Microsoft" /></label>
        <label><span>Current version</span><input v-model="applicationForm.currentVersion" placeholder="126.0.0" /></label>
        <label><span>Latest known version</span><input v-model="applicationForm.latestKnownVersion" placeholder="127.0.0" /></label>
        <label><span>Version source</span><select v-model="applicationForm.versionSource"><option value="manual">Manual</option><option value="url">URL (JSON version)</option><option value="winget">winget index</option></select></label>
        <label><span>Source reference</span><input v-model="applicationForm.versionSourceRef" :disabled="applicationForm.versionSource === 'manual'" placeholder="https://.../latest.json or winget id" /></label>
        <label><span>Current Graph app id</span><input v-model="applicationForm.currentGraphAppId" placeholder="Intune mobileApp id" /></label>
        <label><span>Visibility</span><select v-model="applicationForm.visibility"><option value="personal">Personal</option><option value="shared">Shared</option><option value="group">Group</option></select></label>
        <label v-if="applicationForm.visibility === 'group'"><span>Group</span><select v-model="applicationForm.groupId"><option value="">Choose group</option><option v-for="group in groups" :key="group.id" :value="group.id">{{ group.name }}</option></select></label>
        <label class="toggle modal-toggle"><input v-model="applicationForm.autoCheck" type="checkbox" /><span><strong>Auto-check updates</strong><small>Include in the scheduled upstream version checker.</small></span></label>
        <label class="full"><span>Notes</span><textarea v-model="applicationForm.notes" rows="3" placeholder="Ownership, packaging cadence, rollout policy..." /></label>
        <div class="form-actions modal-actions full">
          <button class="ghost-button" type="button" @click="applicationModalOpen = false">Cancel</button>
          <button v-if="applicationForm.id" class="ghost-button danger-text" type="button" @click="deleteApplicationEntry">Delete</button>
          <button class="primary-action" type="submit"><Save :size="17" />Save application</button>
        </div>
      </form>
    </BaseModal>

    <BaseModal
      :open="importModalOpen"
      title="Import application from tenant"
      eyebrow="MIGRATION AID"
      description="Adopt an existing Intune Win32 app into the catalog using a Graph environment."
      @close="importModalOpen = false"
    >
      <form class="form-grid" @submit.prevent="submitImport">
        <label class="full"><span>Graph environment</span><select v-model="importForm.connectionId" required><option value="">Choose environment</option><option v-for="connection in graphConnections" :key="connection.id" :value="connection.id">{{ connection.name }}</option></select></label>
        <label class="full"><span>Intune mobile app id</span><input v-model="importForm.graphAppId" required placeholder="Graph mobileApp id" /></label>
        <label><span>Visibility</span><select v-model="importForm.visibility"><option value="personal">Personal</option><option value="shared">Shared</option><option value="group">Group</option></select></label>
        <label v-if="importForm.visibility === 'group'"><span>Group</span><select v-model="importForm.groupId"><option value="">Choose group</option><option v-for="group in groups" :key="group.id" :value="group.id">{{ group.name }}</option></select></label>
        <div class="form-actions modal-actions full">
          <button class="ghost-button" type="button" @click="importModalOpen = false">Cancel</button>
          <button class="primary-action" type="submit"><PackagePlus :size="17" />Import</button>
        </div>
      </form>
    </BaseModal>

    <BaseModal
      :open="intuneModalOpen"
      :title="intuneForm.id ? 'Update Intune deployment' : 'New Intune deployment'"
      eyebrow="INTUNE WIN32"
      description="Store PSADT-aware Intune deployment plans with commands, detection, return codes, and assignment-ring intent."
      wide
      @close="intuneModalOpen = false"
    >
      <form class="form-grid intune-deployment-form" @submit.prevent="saveIntuneDeployment">
        <section class="deployment-section full">
          <button class="deployment-section-toggle" type="button" @click="toggleIntuneSection('basics')">
            <span><CloudCog :size="16" /></span>
            <div>
              <strong>Plan basics</strong>
              <small>Name the deployment, bind its source records, and choose visibility.</small>
            </div>
            <ChevronDown :class="{ open: intuneSections.basics }" :size="17" />
          </button>
          <div v-show="intuneSections.basics" class="deployment-section-body three">
            <label><span>Name</span><input v-model="intuneForm.name" required placeholder="Edge Enterprise - Pilot" /></label>
            <label><span>Status</span><select v-model="intuneForm.status"><option>draft</option><option>ready</option><option>published</option><option>retired</option></select></label>
            <label><span>Visibility</span><select v-model="intuneForm.visibility"><option value="personal">Personal</option><option value="shared">Shared</option><option value="group">Group</option></select></label>
            <label><span>PSADT profile</span><select v-model="intuneForm.profileId"><option value="">Manual / none</option><option v-for="profile in profiles" :key="profile.id" :value="profile.id">{{ profile.name }}</option></select></label>
            <label><span>Saved script</span><select v-model="intuneForm.scriptId"><option value="">No saved script</option><option v-for="script in scripts" :key="script.id" :value="script.id">{{ script.name }}</option></select></label>
            <label><span>Catalog application</span><select v-model="intuneForm.applicationId"><option value="">Not linked</option><option v-for="app in applications" :key="app.id" :value="app.id">{{ app.name }}</option></select></label>
            <label><span>Graph environment</span><select v-model="intuneForm.graphConnectionId"><option value="">Not linked</option><option v-for="connection in graphConnections" :key="connection.id" :value="connection.id">{{ connection.name }}</option></select></label>
            <label><span>Graph mobile app ID</span><input v-model="intuneForm.graphAppId" placeholder="Intune mobileApp id" /></label>
            <label v-if="intuneForm.visibility === 'group'"><span>Group</span><select v-model="intuneForm.groupId"><option value="">Choose group</option><option v-for="group in groups" :key="group.id" :value="group.id">{{ group.name }}</option></select></label>
          </div>
        </section>

        <section class="deployment-section full">
          <button class="deployment-section-toggle" type="button" @click="toggleIntuneSection('package')">
            <span><PackageCheck :size="16" /></span>
            <div>
              <strong>Package, commands, and installer intelligence</strong>
              <small>Model the Win32 package, command style, UI behavior, and source files.</small>
            </div>
            <ChevronDown :class="{ open: intuneSections.package }" :size="17" />
          </button>
          <div v-show="intuneSections.package" class="deployment-section-body two">
            <label><span>PSADT source folder</span><input v-model="intuneForm.sourceFolder" placeholder="C:\\Packages\\Edge\\PSADT" /></label>
            <label><span>Intunewin package</span><input v-model="intuneForm.intunewinFile" placeholder="EdgeEnterprise.intunewin" /></label>
            <label><span>Command style</span><select v-model="intuneForm.commandStyle"><option value="v4">PSADT v4 native</option><option value="legacy-v3">Legacy v3 compatible</option></select></label>
            <label><span>UI compatibility</span><select v-model="intuneForm.uiMode"><option value="native-v4">Native v4 user UI</option><option value="serviceui-legacy">Legacy ServiceUI bridge</option><option value="silent">Silent / non-interactive</option></select></label>
            <label><span>Install behavior</span><select v-model="intuneForm.installBehavior"><option value="system">System</option><option value="user">User</option></select></label>
            <label><span>Restart behavior</span><select v-model="intuneForm.restartBehavior"><option value="return-code">Specific return codes</option><option value="suppress">Suppress reboot passthrough</option><option value="intune">Intune managed</option></select></label>
            <div class="installer-analyze span-2">
              <span class="eyebrow">INSTALLER ANALYSIS</span>
              <div class="installer-analyze-row">
                <input v-model="analyzeFileName" placeholder="setup.exe / app.msi" />
                <input v-model="analyzeProductCode" placeholder="MSI product code (optional)" />
                <button class="ghost-button compact" type="button" @click="doAnalyze"><WandSparkles :size="14" />Analyze</button>
              </div>
              <small v-if="installerAnalysis?.message" class="field-hint">{{ installerAnalysis.message }}</small>
              <div v-if="analysisCandidates.length" class="installer-candidates">
                <button v-for="c in analysisCandidates" :key="c.id" type="button" class="status-pill" @click="applyTechnology(c)">{{ c.label }}</button>
              </div>
            </div>
            <label class="span-2"><span>Install command</span><input v-model="intuneForm.installCommand" :placeholder="commandSet(intuneForm.commandStyle, intuneForm.restartBehavior).install" /></label>
            <label class="span-2"><span>Uninstall command</span><input v-model="intuneForm.uninstallCommand" :placeholder="commandSet(intuneForm.commandStyle, intuneForm.restartBehavior).uninstall" /></label>
          </div>
        </section>

        <section class="deployment-section full">
          <button class="deployment-section-toggle" type="button" @click="toggleIntuneSection('requirements')">
            <span><ShieldCheck :size="16" /></span>
            <div>
              <strong>Requirements</strong>
              <small>Architecture, OS baseline, disk requirement, and 32-bit execution mode.</small>
            </div>
            <ChevronDown :class="{ open: intuneSections.requirements }" :size="17" />
          </button>
          <div v-show="intuneSections.requirements" class="deployment-section-body three">
            <label><span>Architecture</span><select v-model="intuneForm.requirements.architecture"><option value="x64">x64</option><option value="x86">x86</option><option value="both">Both</option></select></label>
            <label><span>Minimum OS</span><input v-model="intuneForm.requirements.minOs" placeholder="Windows 10 22H2" /></label>
            <label><span>Disk space MB</span><input v-model.number="intuneForm.requirements.diskSpaceMb" type="number" min="0" /></label>
            <label class="switch-field span-3">
              <input v-model="intuneForm.requirements.runAs32Bit" type="checkbox" />
              <span class="switch-visual" />
              <span><strong>Run as 32-bit process</strong><small>Use only for packages that require 32-bit registry or file redirection.</small></span>
            </label>
          </div>
        </section>

        <section class="deployment-section full">
          <button class="deployment-section-toggle" type="button" @click="toggleIntuneSection('detection')">
            <span><ListChecks :size="16" /></span>
            <div>
              <strong>Detection and return codes</strong>
              <small>Configure detection and add Intune return-code behavior row by row.</small>
            </div>
            <span class="section-count">{{ returnCodeRows.length }} codes</span>
            <ChevronDown :class="{ open: intuneSections.detection }" :size="17" />
          </button>
          <div v-show="intuneSections.detection" class="deployment-section-body">
            <div class="deployment-section-body two">
              <label><span>Detection type</span><select v-model="intuneForm.detectionType"><option value="custom-script">Custom PowerShell</option><option value="msi-product-code">MSI product code</option><option value="file-version">File / version</option><option value="registry">Registry</option></select></label>
              <label><span>Detection rule</span><textarea v-model="intuneForm.detectionRule" rows="4" placeholder="PowerShell detection script, MSI product code, file/version rule, or registry path." /></label>
            </div>
            <div class="structured-list">
              <div class="structured-list-head">
                <div>
                  <strong>Return codes</strong>
                  <small>These rows are saved as Intune return-code objects.</small>
                </div>
                <button class="ghost-button compact" type="button" @click="addReturnCode"><Plus :size="14" />Add code</button>
              </div>
              <article v-for="(row, index) in returnCodeRows" :key="row.localId" class="structured-row return-code-row">
                <label><span>Code</span><input v-model="row.code" placeholder="3010" /></label>
                <label><span>Behavior</span><select v-model="row.type"><option value="success">Success</option><option value="retry">Retry</option><option value="softReboot">Soft reboot</option><option value="hardReboot">Hard reboot</option><option value="failed">Failed</option></select></label>
                <label><span>Meaning</span><input v-model="row.meaning" placeholder="Install completed and reboot is required." /></label>
                <button class="icon-action danger-text" type="button" title="Remove return code" @click="removeReturnCode(index)"><Trash2 :size="15" /></button>
              </article>
            </div>
          </div>
        </section>

        <section class="deployment-section full">
          <button class="deployment-section-toggle" type="button" @click="toggleIntuneSection('assignments')">
            <span><Braces :size="16" /></span>
            <div>
              <strong>Assignment rings</strong>
              <small>Add pilot, broad, uninstall, and exclusion targets without pipe-delimited strings.</small>
            </div>
            <span class="section-count">{{ assignmentRows.length }} rings</span>
            <ChevronDown :class="{ open: intuneSections.assignments }" :size="17" />
          </button>
          <div v-show="intuneSections.assignments" class="structured-list">
            <div class="structured-list-head">
              <div>
                <strong>Assignments</strong>
                <small>Use target mode for groups, all devices, or all users. Filters and auto-update are optional.</small>
              </div>
              <button class="ghost-button compact" type="button" @click="addAssignment"><Plus :size="14" />Add assignment</button>
            </div>
            <article v-for="(row, index) in assignmentRows" :key="row.localId" class="structured-row assignment-row">
              <label><span>Ring</span><input v-model="row.ring" placeholder="Pilot" /></label>
              <label><span>Intent</span><select v-model="row.intent"><option value="available">Available</option><option value="required">Required</option><option value="uninstall">Uninstall</option><option value="exclude">Exclude</option></select></label>
              <label><span>Target mode</span><select v-model="row.groupMode"><option value="group">Group</option><option value="allDevices">All devices</option><option value="allUsers">All users</option></select></label>
              <label v-if="row.groupMode === 'group'"><span>Group name</span><input v-model="row.groupName" placeholder="IT Pilot Devices" /></label>
              <label v-if="row.groupMode === 'group'"><span>Entra group object ID</span><input v-model="row.groupId" placeholder="00000000-0000-0000-0000-000000000000" /></label>
              <label><span>Filter type</span><select v-model="row.filterType"><option value="none">No filter</option><option value="include">Include filter</option><option value="exclude">Exclude filter</option></select></label>
              <label v-if="row.filterType !== 'none'"><span>Filter ID</span><input v-model="row.filterId" placeholder="Assignment filter id" /></label>
              <label class="switch-field compact-switch">
                <input v-model="row.autoUpdate" type="checkbox" />
                <span class="switch-visual" />
                <span><strong>Auto-update</strong><small>Apply future app versions to this ring.</small></span>
              </label>
              <label class="span-all"><span>Notes</span><input v-model="row.notes" placeholder="Validation ring before broad assignment." /></label>
              <button class="icon-action danger-text" type="button" title="Remove assignment" @click="removeAssignment(index)"><Trash2 :size="15" /></button>
            </article>
          </div>
        </section>

        <section class="deployment-section full">
          <button class="deployment-section-toggle" type="button" @click="toggleIntuneSection('relationships')">
            <span><Puzzle :size="16" /></span>
            <div>
              <strong>Relationships and promotion</strong>
              <small>Model supersedence, dependencies, and optional soak-based promotion.</small>
            </div>
            <span class="section-count">{{ relationshipRows.length }} links</span>
            <ChevronDown :class="{ open: intuneSections.relationships }" :size="17" />
          </button>
          <div v-show="intuneSections.relationships" class="deployment-section-body">
            <label class="switch-field">
              <input :checked="autoPromoteEnabled" type="checkbox" @change="setAutoPromoteEnabled($event.target.checked)" />
              <span class="switch-visual" />
              <span><strong>Enable auto-promotion</strong><small>After publish, promote a target ring once the soak window expires.</small></span>
            </label>
            <div v-if="autoPromoteEnabled" class="deployment-section-body three">
              <label><span>After hours</span><input v-model.number="intuneForm.autoPromoteAfterHours" type="number" min="1" /></label>
              <label><span>Ring</span><input v-model="intuneForm.autoPromoteRing" placeholder="Broad" /></label>
              <label><span>Intent</span><select v-model="intuneForm.autoPromoteIntent"><option value="required">Required</option><option value="available">Available</option><option value="uninstall">Uninstall</option></select></label>
            </div>
            <div class="structured-list">
              <div class="structured-list-head">
                <div>
                  <strong>App relationships</strong>
                  <small>Target app IDs are Intune mobileApp IDs.</small>
                </div>
                <button class="ghost-button compact" type="button" @click="addRelationship"><Plus :size="14" />Add relationship</button>
              </div>
              <article v-for="(row, index) in relationshipRows" :key="row.localId" class="structured-row relationship-row">
                <label><span>Kind</span><select v-model="row.kind"><option value="supersedence">Supersedence</option><option value="dependency">Dependency</option></select></label>
                <label><span>Mode</span><select v-model="row.mode"><option v-if="row.kind === 'supersedence'" value="update">Update</option><option v-if="row.kind === 'supersedence'" value="replace">Replace</option><option v-if="row.kind === 'dependency'" value="detect">Detect only</option><option v-if="row.kind === 'dependency'" value="autoInstall">Auto-install</option></select></label>
                <label><span>Target app ID</span><input v-model="row.targetAppId" placeholder="mobileApp id" /></label>
                <label><span>Target name</span><input v-model="row.targetName" placeholder="Old VPN 2.9" /></label>
                <button class="icon-action danger-text" type="button" title="Remove relationship" @click="removeRelationship(index)"><Trash2 :size="15" /></button>
              </article>
            </div>
          </div>
        </section>

        <section class="deployment-section full">
          <button class="deployment-section-toggle" type="button" @click="toggleIntuneSection('notes')">
            <span><ClipboardCheck :size="16" /></span>
            <div>
              <strong>Notes</strong>
              <small>Operator notes, packaging status, rollout context, and review details.</small>
            </div>
            <ChevronDown :class="{ open: intuneSections.notes }" :size="17" />
          </button>
          <div v-show="intuneSections.notes" class="deployment-section-body">
            <label><span>Notes</span><textarea v-model="intuneForm.notes" rows="3" placeholder="Deployment owner notes, Graph object IDs, packaging status, rollout decisions..." /></label>
          </div>
        </section>
        <div class="form-actions modal-actions full">
          <button class="ghost-button" type="button" @click="intuneModalOpen = false">Cancel</button>
          <button v-if="intuneForm.id" class="ghost-button danger-text" type="button" @click="deleteIntuneDeployment">Delete</button>
          <button class="primary-action" type="submit"><Save :size="17" />Save deployment</button>
        </div>
      </form>
    </BaseModal>

    <BaseModal
      :open="profileModalOpen"
      :title="profileForm.id ? 'Update PSADT profile' : 'New PSADT profile'"
      eyebrow="PSADT PROFILE"
      description="Profiles are reusable deployment blueprints. They can generate a script scaffold and package command lines for Intune or classic deployment systems."
      wide
      @close="profileModalOpen = false"
    >
      <form class="form-grid" @submit.prevent="saveProfile">
        <label><span>Profile name</span><input v-model="profileForm.name" required placeholder="Microsoft Edge Enterprise" /></label>
        <label><span>Vendor</span><input v-model="profileForm.appVendor" placeholder="Microsoft" /></label>
        <label><span>Application name</span><input v-model="profileForm.appName" :disabled="profileForm.zeroConfig" placeholder="Edge" /></label>
        <label><span>Version</span><input v-model="profileForm.appVersion" placeholder="126.0.0" /></label>
        <label><span>Architecture</span><select v-model="profileForm.appArch"><option value="x64">x64</option><option value="x86">x86</option><option value="neutral">Neutral</option></select></label>
        <label><span>Language</span><input v-model="profileForm.appLang" placeholder="EN" /></label>
        <label><span>Revision</span><input v-model="profileForm.appRevision" placeholder="01" /></label>
        <label><span>Toolkit template</span><select v-model="profileForm.templateVersion"><option value="v4">v4 native</option><option value="v3">v3 compatibility</option></select></label>
        <label><span>Deployment type</span><select v-model="profileForm.deploymentType"><option>Install</option><option>Uninstall</option><option>Repair</option></select></label>
        <label><span>Deploy mode</span><select v-model="profileForm.deployMode"><option>Auto</option><option>Interactive</option><option>Silent</option><option>NonInteractive</option></select></label>
        <label><span>Visibility</span><select v-model="profileForm.visibility"><option value="personal">Personal</option><option value="shared">Shared</option><option value="group">Group</option></select></label>
        <label v-if="profileForm.visibility === 'group'"><span>Group</span><select v-model="profileForm.groupId"><option :value="null">Choose group</option><option v-for="group in groups" :key="group.id" :value="group.id">{{ group.name }}</option></select></label>
        <label class="toggle modal-toggle"><input v-model="profileForm.requireAdmin" type="checkbox" /><span><strong>Require admin</strong><small>Render RequireAdmin in the ADTSession metadata.</small></span></label>
        <label class="toggle modal-toggle"><input v-model="profileForm.zeroConfig" type="checkbox" /><span><strong>Zero-config MSI</strong><small>Leave AppName empty and use one MSI/MST/MSP/WIM set in Files.</small></span></label>
        <label class="toggle modal-toggle"><input v-model="profileForm.suppressReboot" type="checkbox" /><span><strong>Suppress reboot passthrough</strong><small>Add -SuppressRebootPassThru to command generation.</small></span></label>
        <label class="toggle modal-toggle"><input v-model="profileForm.uiPlan.welcome" type="checkbox" /><span><strong>Welcome UI</strong><small>Render Show-ADTInstallationWelcome in pre-phase.</small></span></label>
        <label class="full"><span>Close processes</span><input v-model="closeProcessesText" placeholder="winword:Microsoft Word, excel:Microsoft Excel" /></label>
        <label class="full"><span>Install task</span><input v-model="installTaskText" placeholder="setup.exe|/S or app.msi|TRANSFORMS=app.mst" /></label>
        <div class="form-actions modal-actions full">
          <button class="ghost-button" type="button" @click="profileModalOpen = false">Cancel</button>
          <button v-if="profileForm.id" class="ghost-button danger-text" type="button" @click="deleteProfile">Delete</button>
          <button class="primary-action" type="submit"><Save :size="17" />Save profile</button>
        </div>
      </form>
    </BaseModal>
  </section>
</template>

<script setup>
import { computed, reactive, ref, watch } from 'vue';
import {
  BookOpenText, Braces, ChevronDown, ClipboardCheck, CloudCog, FilePlus2, FolderTree, Link2, ListChecks, PackageCheck, PackagePlus, Plus, Puzzle, RefreshCw,
  Save, ShieldCheck, SlidersHorizontal, TerminalSquare, Trash2, WandSparkles
} from '@lucide/vue';
import BaseModal from '../components/ui/BaseModal.vue';
import ResourceTable from '../components/ui/ResourceTable.vue';
import RelationshipGraph from '../components/RelationshipGraph.vue';

const props = defineProps({
  catalog: { type: Object, default: () => ({}) },
  profiles: { type: Array, default: () => [] },
  scripts: { type: Array, default: () => [] },
  intuneDeployments: { type: Array, default: () => [] },
  graphConnections: { type: Array, default: () => [] },
  graphStatusResult: { type: Object, default: null },
  graphAuditResult: { type: Array, default: () => [] },
  driftResult: { type: Object, default: null },
  builderStatus: { type: Object, default: null },
  assets: { type: Array, default: () => [] },
  applications: { type: Array, default: () => [] },
  changeRequests: { type: Array, default: () => [] },
  reportingOverview: { type: Object, default: null },
  installerAnalysis: { type: Object, default: null },
  validationResult: { type: Object, default: null },
  migrationPlanResult: { type: Object, default: null },
  groups: { type: Array, default: () => [] }
});

const emit = defineEmits([
  'refresh',
  'save-profile',
  'delete-profile',
  'render-profile',
  'create-script',
  'insert-snippet',
  'validate-psadt',
  'plan-migration',
  'apply-migration',
  'save-intune-deployment',
  'delete-intune-deployment',
  'save-graph-connection',
  'delete-graph-connection',
  'test-graph-connection',
  'link-graph-app',
  'sync-graph-status',
  'load-graph-status',
  'load-graph-audit',
  'publish-graph-app',
  'upload-graph-content',
  'assign-graph-app',
  'set-graph-relationships',
  'check-drift',
  'reconcile-graph-app',
  'new-version',
  'build-intunewin',
  'save-application',
  'delete-application',
  'check-application-update',
  'import-application',
  'refresh-governance',
  'approve-change-request',
  'reject-change-request',
  'analyze-installer'
]);

const profileModalOpen = ref(false);
const intuneModalOpen = ref(false);
const graphModalOpen = ref(false);
const profileSearch = ref('');
const intuneSearch = ref('');
const activePublishStep = ref(0);
const selectedIntuneDeploymentId = ref('');
const graphDeploymentId = ref('');
const graphConnectionId = ref('');
const graphAppId = ref('');
const validationTarget = ref('script');
const validationScriptId = ref('');
const validationProfileId = ref('');
const validationPlatform = ref('intune');
const validationRaw = ref('');
const migrationTarget = ref('script');
const migrationScriptId = ref('');
const migrationTargetVersion = ref('4.2.0');
const migrationRaw = ref('');
const closeProcessesText = ref('');
const installTaskText = ref('');
const returnCodesText = ref('');
const assignmentsText = ref('');
const relationshipsText = ref('');
const returnCodeRows = ref([]);
const assignmentRows = ref([]);
const relationshipRows = ref([]);
const contentAssetId = ref('');
const buildSetupFile = ref('');
const analyzeFileName = ref('');
const analyzeProductCode = ref('');
const analysisCandidates = ref([]);
const profileForm = reactive(defaultProfile());
const intuneForm = reactive(defaultIntuneDeployment());
const graphForm = reactive(defaultGraphConnection());
const applicationModalOpen = ref(false);
const importModalOpen = ref(false);
const applicationForm = reactive(defaultApplication());
const importForm = reactive({ connectionId: '', graphAppId: '', visibility: 'shared', groupId: '' });
const intuneSections = reactive({
  basics: true,
  package: false,
  requirements: false,
  detection: false,
  assignments: false,
  relationships: false,
  notes: false
});

const profileColumns = [
  { key: 'name', label: 'Profile' },
  { key: 'app', label: 'Application', sortable: false },
  { key: 'mode', label: 'Mode', sortable: false },
  { key: 'visibility', label: 'Visibility' },
  { key: 'flags', label: 'Flags', sortable: false },
  { key: 'actions', label: 'Actions', sortable: false, class: 'table-actions-cell' }
];
const intuneColumns = [
  { key: 'name', label: 'Deployment' },
  { key: 'profile', label: 'Source', sortable: false },
  { key: 'status', label: 'Status' },
  { key: 'package', label: 'Package', sortable: false },
  { key: 'detectionType', label: 'Detection' },
  { key: 'assignments', label: 'Assignments', sortable: false },
  { key: 'actions', label: 'Actions', sortable: false, class: 'table-actions-cell' }
];
const fallbackPublishingSteps = [
  { id: 'source', title: 'Prepare source', summary: 'Place installers in Files, supporting content in SupportFiles, and toolkit assets/config in the PSADT folder.' },
  { id: 'commands', title: 'Program commands', summary: 'Generate the correct install and uninstall command style for PSADT v4 or legacy v3 packages.' },
  { id: 'requirements', title: 'Requirements', summary: 'Capture architecture, minimum Windows baseline, disk needs, and 32-bit execution behavior.' },
  { id: 'detection', title: 'Detection', summary: 'Define MSI, file/version, registry, or custom PowerShell detection that Intune can trust.' },
  { id: 'returns', title: 'Return codes', summary: 'Map success, retry/defer, reboot, PSADT failure, and custom ranges.' },
  { id: 'assignments', title: 'Assignments', summary: 'Track pilot, broad, and exclusion rings with intent and target group notes.' },
  { id: 'review', title: 'Review', summary: 'Confirm UI context, ServiceUI compatibility, package path, Graph app id, and rollout readiness.' }
];

const sourceMap = computed(() => new Map((props.catalog.sources || []).map((source) => [source.id, source.title])));
const publishingSteps = computed(() => props.catalog.intune?.publishingSteps?.length ? props.catalog.intune.publishingSteps : fallbackPublishingSteps);
const currentPublishingStep = computed(() => publishingSteps.value[activePublishStep.value] || publishingSteps.value[0]);
const selectedIntuneDeployment = computed(() => props.intuneDeployments.find((deployment) => deployment.id === selectedIntuneDeploymentId.value) || null);
const currentDeployment = computed(() => selectedIntuneDeployment.value || defaultIntuneDeployment());
const recommendedCommands = computed(() => commandSet(currentDeployment.value.commandStyle, currentDeployment.value.restartBehavior));
const sourceChecklist = computed(() => [
  currentDeployment.value.sourceFolder ? `Source folder: ${currentDeployment.value.sourceFolder}` : 'Choose the PSADT source folder before wrapping.',
  currentDeployment.value.intunewinFile ? `.intunewin: ${currentDeployment.value.intunewinFile}` : 'Wrap the whole PSADT folder with Microsoft Win32 Content Prep Tool.',
  currentDeployment.value.commandStyle === 'v4' ? 'Content root should include Invoke-AppDeployToolkit.exe.' : 'Legacy content root should include Deploy-Application.exe.'
]);
const compatibilityFindings = computed(() => buildCompatibilityFindings(currentDeployment.value));
const compatibilityScore = computed(() => Math.max(0, 100 - compatibilityFindings.value.reduce((total, finding) => total + finding.penalty, 0)));
const filteredProfiles = computed(() => {
  const query = profileSearch.value.trim().toLowerCase();
  if (!query) return props.profiles;
  return props.profiles.filter((profile) => [
    profile.name,
    profile.appVendor,
    profile.appName,
    profile.appVersion,
    profile.deploymentType,
    profile.deployMode,
    profile.visibility
  ].filter(Boolean).join(' ').toLowerCase().includes(query));
});
const filteredIntuneDeployments = computed(() => {
  const query = intuneSearch.value.trim().toLowerCase();
  if (!query) return props.intuneDeployments;
  return props.intuneDeployments.filter((deployment) => [
    deployment.name,
    deployment.profileName,
    deployment.scriptName,
    deployment.status,
    deployment.detectionType,
    deployment.visibility,
    deployment.assignments?.map((item) => item.ring).join(' ')
  ].filter(Boolean).join(' ').toLowerCase().includes(query));
});
const functionCategoryCounts = computed(() => {
  const counts = new Map();
  for (const fn of props.catalog.functions || []) counts.set(fn.category, (counts.get(fn.category) || 0) + 1);
  return [...counts.entries()].map(([category, count]) => ({ category, count })).sort((a, b) => a.category.localeCompare(b.category));
});
const canValidate = computed(() => {
  if (validationTarget.value === 'script') return Boolean(validationScriptId.value);
  if (validationTarget.value === 'profile') return Boolean(validationProfileId.value);
  return Boolean(validationRaw.value.trim());
});
const canPlanMigration = computed(() => {
  if (migrationTarget.value === 'script') return Boolean(migrationScriptId.value);
  return Boolean(migrationRaw.value.trim());
});
const canLinkGraph = computed(() => Boolean(graphDeploymentId.value && graphConnectionId.value && graphAppId.value.trim()));
const selectedWriteConnection = computed(() => props.graphConnections.find((connection) => connection.id === graphConnectionId.value) || null);
const selectedGraphDeployment = computed(() => props.intuneDeployments.find((deployment) => deployment.id === graphDeploymentId.value) || null);
const intunewinAssets = computed(() => props.assets.filter((asset) => /\.intunewin$/i.test(asset.originalName || asset.name || '')));
const pendingChangeRequests = computed(() => props.changeRequests.filter((request) => request.status === 'pending'));
const autoPromoteEnabled = computed(() => Number(intuneForm.autoPromoteAfterHours) > 0 || Boolean(intuneForm.autoPromoteRing));

function sourceTitle(sourceId) {
  return sourceMap.value.get(sourceId) || sourceId;
}

function openProfileModal(profile = null) {
  Object.assign(profileForm, defaultProfile(), profile || {});
  profileForm.uiPlan = { welcome: profile?.uiPlan?.welcome !== false };
  closeProcessesText.value = (profile?.closeProcesses || []).map((item) => `${item.name}:${item.description || item.name}`).join(', ');
  installTaskText.value = (profile?.installTasks || []).map((item) => `${item.filePath}|${item.arguments || ''}`).join(', ');
  profileModalOpen.value = true;
}

function openIntuneDeploymentModal(deployment = null) {
  Object.assign(intuneForm, defaultIntuneDeployment(), deployment || {});
  intuneForm.profileId = deployment?.profileId || '';
  intuneForm.scriptId = deployment?.scriptId || '';
  intuneForm.groupId = deployment?.groupId || '';
  intuneForm.requirements = { ...defaultIntuneDeployment().requirements, ...(deployment?.requirements || {}) };
  returnCodeRows.value = normalizeReturnCodes(deployment?.returnCodes || defaultIntuneDeployment().returnCodes);
  assignmentRows.value = normalizeAssignments(deployment?.assignments || defaultIntuneDeployment().assignments);
  relationshipRows.value = normalizeRelationships(deployment?.relationships || []);
  Object.assign(intuneSections, {
    basics: true,
    package: false,
    requirements: false,
    detection: false,
    assignments: false,
    relationships: Boolean((deployment?.relationships || []).length || deployment?.autoPromoteAfterHours || deployment?.autoPromoteRing),
    notes: Boolean(deployment?.notes)
  });
  intuneModalOpen.value = true;
}

function toggleIntuneSection(section) {
  intuneSections[section] = !intuneSections[section];
}

function defaultApplication() {
  return {
    id: null,
    name: '',
    vendor: '',
    currentVersion: '',
    latestKnownVersion: '',
    versionSource: 'manual',
    versionSourceRef: '',
    currentGraphAppId: '',
    autoCheck: false,
    notes: '',
    visibility: 'shared',
    groupId: ''
  };
}

function openApplicationModal(application = null) {
  Object.assign(applicationForm, defaultApplication(), application || {});
  applicationForm.groupId = application?.groupId || '';
  applicationModalOpen.value = true;
}

function saveApplication() {
  emit('save-application', { ...applicationForm, groupId: applicationForm.groupId || null });
  applicationModalOpen.value = false;
}

function deleteApplicationEntry() {
  const id = applicationForm.id;
  applicationModalOpen.value = false;
  emit('delete-application', id);
}

function openImportModal() {
  Object.assign(importForm, { connectionId: props.graphConnections[0]?.id || '', graphAppId: '', visibility: 'shared', groupId: '' });
  importModalOpen.value = true;
}

function submitImport() {
  emit('import-application', { ...importForm, groupId: importForm.groupId || null });
  importModalOpen.value = false;
}

function openGraphConnectionModal(connection = null) {
  Object.assign(graphForm, defaultGraphConnection(), connection || {});
  graphForm.clientSecret = '';
  graphForm.groupId = connection?.groupId || '';
  graphModalOpen.value = true;
}

function saveProfile() {
  const payload = {
    ...profileForm,
    closeProcesses: parseCloseProcesses(closeProcessesText.value),
    installTasks: parseInstallTasks(installTaskText.value)
  };
  emit('save-profile', payload);
  profileModalOpen.value = false;
}

function deleteProfile() {
  const id = profileForm.id;
  profileModalOpen.value = false;
  emit('delete-profile', id);
}

function doAnalyze() {
  if (!analyzeFileName.value.trim()) return;
  emit('analyze-installer', { fileName: analyzeFileName.value.trim(), productCode: analyzeProductCode.value.trim() });
}

function applyTechnology(candidate) {
  if (candidate.install) intuneForm.installCommand = candidate.install;
  if (candidate.uninstall) intuneForm.uninstallCommand = candidate.uninstall;
  if (candidate.detection === 'msi' && analyzeProductCode.value.trim()) {
    intuneForm.detectionType = 'msi-product-code';
    intuneForm.detectionRule = analyzeProductCode.value.trim();
  }
}

// Apply the analysis to the form when the parent resolves it.
watch(() => props.installerAnalysis, (analysis) => {
  if (!analysis) return;
  analysisCandidates.value = analysis.candidates || [];
  if (analysis.primary) applyTechnology(analysis.primary);
});

function saveIntuneDeployment() {
  const commands = commandSet(intuneForm.commandStyle, intuneForm.restartBehavior);
  emit('save-intune-deployment', {
    ...intuneForm,
    profileId: intuneForm.profileId || null,
    scriptId: intuneForm.scriptId || null,
    groupId: intuneForm.groupId || null,
    installCommand: intuneForm.installCommand || commands.install,
    uninstallCommand: intuneForm.uninstallCommand || commands.uninstall,
    returnCodes: buildReturnCodes(),
    assignments: buildAssignments(),
    relationships: buildRelationships()
  });
  intuneModalOpen.value = false;
}

function deleteIntuneDeployment() {
  const id = intuneForm.id;
  intuneModalOpen.value = false;
  emit('delete-intune-deployment', id);
}

function saveGraphConnection() {
  emit('save-graph-connection', { ...graphForm, groupId: graphForm.groupId || null });
  graphModalOpen.value = false;
}

function deleteGraphConnection() {
  const id = graphForm.id;
  graphModalOpen.value = false;
  emit('delete-graph-connection', id);
}

function hydrateGraphTarget() {
  const deployment = props.intuneDeployments.find((item) => item.id === graphDeploymentId.value);
  graphConnectionId.value = deployment?.graphConnectionId || graphConnectionId.value || props.graphConnections[0]?.id || '';
  graphAppId.value = deployment?.graphAppId || '';
}

function linkGraphApp() {
  emit('link-graph-app', { deploymentId: graphDeploymentId.value, connectionId: graphConnectionId.value, graphAppId: graphAppId.value.trim() });
}

function syncGraphStatus() {
  emit('sync-graph-status', { deploymentId: graphDeploymentId.value, connectionId: graphConnectionId.value, graphAppId: graphAppId.value.trim(), mode: 'reports' });
}

function publishGraphApp() {
  emit('publish-graph-app', { deploymentId: graphDeploymentId.value, connectionId: graphConnectionId.value });
}

function uploadGraphContent() {
  emit('upload-graph-content', { deploymentId: graphDeploymentId.value, connectionId: graphConnectionId.value, assetId: contentAssetId.value });
}

function assignGraphApp() {
  emit('assign-graph-app', { deploymentId: graphDeploymentId.value, connectionId: graphConnectionId.value });
}

function setGraphRelationships() {
  emit('set-graph-relationships', { deploymentId: graphDeploymentId.value, connectionId: graphConnectionId.value });
}

function checkDrift() {
  emit('check-drift', { deploymentId: graphDeploymentId.value, connectionId: graphConnectionId.value });
}

function reconcileGraphApp() {
  emit('reconcile-graph-app', { deploymentId: graphDeploymentId.value, connectionId: graphConnectionId.value });
}

function buildIntunewin() {
  emit('build-intunewin', { deploymentId: graphDeploymentId.value, setupFile: buildSetupFile.value.trim() });
}

function graphStatusClass(state = '') {
  if (state === 'installed') return 'completed';
  if (state === 'failed') return 'critical';
  if (state === 'pending') return 'warning';
  return 'info';
}

function applyGraphCloudDefaults() {
  const defaults = {
    global: ['https://graph.microsoft.com', 'https://login.microsoftonline.com'],
    gcc: ['https://graph.microsoft.com', 'https://login.microsoftonline.com'],
    gcchigh: ['https://graph.microsoft.us', 'https://login.microsoftonline.us'],
    dod: ['https://dod-graph.microsoft.us', 'https://login.microsoftonline.us'],
    china: ['https://microsoftgraph.chinacloudapi.cn', 'https://login.chinacloudapi.cn']
  };
  const next = defaults[graphForm.cloud];
  if (!next) return;
  graphForm.graphBaseUrl = next[0];
  graphForm.authorityHost = next[1];
}

function runValidation() {
  emit('validate-psadt', {
    platform: validationPlatform.value,
    scriptId: validationTarget.value === 'script' ? validationScriptId.value : undefined,
    profileId: validationTarget.value === 'profile' ? validationProfileId.value : undefined,
    content: validationTarget.value === 'raw' ? validationRaw.value : undefined
  });
}

function migrationPayload(createScript = false) {
  return {
    targetVersion: migrationTargetVersion.value,
    createScript,
    scriptId: migrationTarget.value === 'script' ? migrationScriptId.value : undefined,
    content: migrationTarget.value === 'raw' ? migrationRaw.value : undefined
  };
}

function planMigration() {
  emit('plan-migration', migrationPayload(false));
}

function applyMigration() {
  emit('apply-migration', migrationPayload(true));
}

function commandSet(commandStyle = 'v4', restartBehavior = 'return-code') {
  const suppress = restartBehavior === 'suppress' ? ' -SuppressRebootPassThru' : '';
  if (commandStyle === 'legacy-v3') {
    return {
      install: `Deploy-Application.exe -DeploymentType "Install" -DeployMode "Interactive"${suppress}`,
      uninstall: `Deploy-Application.exe -DeploymentType "Uninstall" -DeployMode "Interactive"${suppress}`
    };
  }
  return {
    install: `Invoke-AppDeployToolkit.exe -DeploymentType Install${suppress}`,
    uninstall: `Invoke-AppDeployToolkit.exe -DeploymentType Uninstall${suppress}`
  };
}

function stepComplete(stepId) {
  const deployment = currentDeployment.value;
  const rules = {
    source: Boolean(deployment.sourceFolder && deployment.intunewinFile),
    commands: Boolean(deployment.installCommand && deployment.uninstallCommand),
    requirements: Boolean(deployment.requirements?.architecture && deployment.requirements?.minOs),
    detection: Boolean(deployment.detectionType && deployment.detectionRule),
    returns: Boolean(deployment.returnCodes?.length),
    assignments: Boolean(deployment.assignments?.length),
    review: compatibilityScore.value >= 90
  };
  return Boolean(rules[stepId]);
}

function buildCompatibilityFindings(deployment) {
  const findings = [];
  if (!deployment.sourceFolder) findings.push({ id: 'source-folder', label: 'source', level: 'warning', penalty: 8, text: 'PSADT source folder is not recorded.' });
  if (!deployment.intunewinFile) findings.push({ id: 'intunewin', label: 'intunewin', level: 'warning', penalty: 8, text: '.intunewin package file is not recorded.' });
  if (!deployment.installCommand || !deployment.uninstallCommand) findings.push({ id: 'commands', label: 'commands', level: 'error', penalty: 15, text: 'Install and uninstall commands are required.' });
  if (deployment.commandStyle === 'v4' && /Deploy-Application/i.test(`${deployment.installCommand} ${deployment.uninstallCommand}`)) {
    findings.push({ id: 'legacy-command', label: 'legacy cmd', level: 'error', penalty: 14, text: 'PSADT v4 plans should use Invoke-AppDeployToolkit.exe, not Deploy-Application.exe.' });
  }
  if (deployment.commandStyle === 'legacy-v3' && deployment.uiMode !== 'serviceui-legacy') {
    findings.push({ id: 'legacy-ui', label: 'legacy ui', level: 'warning', penalty: 8, text: 'Legacy v3 interactive Intune packages usually need the ServiceUI bridge.' });
  }
  if (deployment.commandStyle === 'v4' && deployment.uiMode === 'serviceui-legacy') {
    findings.push({ id: 'serviceui-v4', label: 'serviceui', level: 'critical', penalty: 20, text: 'PSADT v4.1+ Intune UI should use native session handling instead of ServiceUI.' });
  }
  if (deployment.installBehavior !== 'system') {
    findings.push({ id: 'user-install', label: 'behavior', level: 'warning', penalty: 6, text: 'System install behavior is recommended for enterprise PSADT Win32 apps.' });
  }
  if (!deployment.detectionRule) findings.push({ id: 'detection', label: 'detection', level: 'error', penalty: 15, text: 'Detection rule is required before publishing.' });
  if (!deployment.returnCodes?.some((row) => String(row.code) === '1602')) findings.push({ id: 'defer-code', label: '1602', level: 'warning', penalty: 5, text: 'Map 1602 for user deferral/retry behavior.' });
  if (!deployment.returnCodes?.some((row) => ['3010', '1703'].includes(String(row.code)))) findings.push({ id: 'reboot-code', label: 'reboot', level: 'warning', penalty: 5, text: 'Map a soft reboot code such as 3010 or legacy 1703.' });
  if (!deployment.assignments?.length) findings.push({ id: 'assignments', label: 'rings', level: 'warning', penalty: 8, text: 'At least one assignment ring should be recorded.' });
  if (!findings.length) findings.push({ id: 'ready', label: 'ready', level: 'completed', penalty: 0, text: 'Plan is compatible with the modeled PSADT/Intune publishing guidance.' });
  return findings;
}

function parseCloseProcesses(value) {
  return value.split(',').map((part) => part.trim()).filter(Boolean).map((part) => {
    const [name, description] = part.split(':');
    return { name: name.trim(), description: (description || name).trim() };
  });
}

function parseInstallTasks(value) {
  return value.split(',').map((part) => part.trim()).filter(Boolean).map((part) => {
    const [filePath, args = ''] = part.split('|');
    const extension = filePath.split('.').pop()?.toLowerCase();
    return {
      type: extension === 'msi' ? 'msi' : extension === 'msp' ? 'msp' : 'exe',
      phase: 'Install',
      filePath: filePath.trim(),
      arguments: args.trim(),
      secureArguments: false
    };
  });
}

function rowId(prefix) {
  return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
}

function normalizeReturnCodes(rows = []) {
  return rows.map((row) => ({
    localId: row.localId || rowId('return'),
    code: row.code ?? '',
    type: row.type || 'success',
    meaning: row.meaning || ''
  }));
}

function normalizeAssignments(rows = []) {
  return rows.map((row) => ({
    localId: row.localId || rowId('assign'),
    ring: row.ring || '',
    intent: row.intent || 'required',
    groupName: row.groupName || '',
    groupId: row.groupId || '',
    groupMode: row.groupMode || inferAssignmentMode(row.groupName),
    filterId: row.filterId || '',
    filterType: row.filterType || 'none',
    autoUpdate: Boolean(row.autoUpdate),
    notes: row.notes || ''
  }));
}

function normalizeRelationships(rows = []) {
  return rows.map((row) => ({
    localId: row.localId || rowId('relationship'),
    kind: row.kind === 'dependency' ? 'dependency' : 'supersedence',
    targetAppId: row.targetAppId || '',
    targetName: row.targetName || '',
    mode: row.mode || (row.kind === 'dependency' ? 'detect' : 'update')
  }));
}

function inferAssignmentMode(groupName = '') {
  if (/all\s*devices/i.test(groupName)) return 'allDevices';
  if (/all\s*(licensed\s*)?users/i.test(groupName)) return 'allUsers';
  return 'group';
}

function addReturnCode() {
  returnCodeRows.value.push({ localId: rowId('return'), code: '', type: 'success', meaning: '' });
}

function removeReturnCode(index) {
  returnCodeRows.value.splice(index, 1);
}

function addAssignment() {
  assignmentRows.value.push({
    localId: rowId('assign'),
    ring: '',
    intent: 'required',
    groupMode: 'group',
    groupName: '',
    groupId: '',
    filterType: 'none',
    filterId: '',
    autoUpdate: false,
    notes: ''
  });
}

function removeAssignment(index) {
  assignmentRows.value.splice(index, 1);
}

function addRelationship() {
  relationshipRows.value.push({ localId: rowId('relationship'), kind: 'supersedence', mode: 'update', targetAppId: '', targetName: '' });
}

function removeRelationship(index) {
  relationshipRows.value.splice(index, 1);
}

function setAutoPromoteEnabled(enabled) {
  if (enabled) {
    intuneForm.autoPromoteAfterHours = Number(intuneForm.autoPromoteAfterHours) || 24;
    intuneForm.autoPromoteRing = intuneForm.autoPromoteRing || 'Broad';
    intuneForm.autoPromoteIntent = intuneForm.autoPromoteIntent || 'required';
    return;
  }
  intuneForm.autoPromoteAfterHours = 0;
  intuneForm.autoPromoteRing = '';
}

function buildReturnCodes() {
  return returnCodeRows.value
    .map((row) => ({ code: String(row.code ?? '').trim(), type: row.type || 'success', meaning: row.meaning?.trim() || '' }))
    .filter((row) => row.code);
}

function buildAssignments() {
  return assignmentRows.value
    .map((row) => ({
      ring: row.ring?.trim() || '',
      intent: row.intent || 'required',
      groupMode: row.groupMode || 'group',
      groupName: row.groupMode === 'allDevices' ? 'All Devices' : row.groupMode === 'allUsers' ? 'All Users' : row.groupName?.trim() || '',
      groupId: row.groupMode === 'group' ? row.groupId?.trim() || '' : '',
      filterType: row.filterType || 'none',
      filterId: row.filterType === 'none' ? '' : row.filterId?.trim() || '',
      autoUpdate: Boolean(row.autoUpdate),
      notes: row.notes?.trim() || ''
    }))
    .filter((row) => row.ring);
}

function buildRelationships() {
  return relationshipRows.value
    .map((row) => ({
      kind: row.kind === 'dependency' ? 'dependency' : 'supersedence',
      targetAppId: row.targetAppId?.trim() || '',
      targetName: row.targetName?.trim() || '',
      mode: row.kind === 'dependency'
        ? ['detect', 'autoInstall'].includes(row.mode) ? row.mode : 'detect'
        : ['update', 'replace'].includes(row.mode) ? row.mode : 'update'
    }))
    .filter((row) => row.targetAppId);
}

function parseReturnCodes(value) {
  return value.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => {
    const [code, type = 'success', meaning = ''] = line.split('|');
    return { code: code.trim(), type: type.trim(), meaning: meaning.trim() };
  });
}

function parseAssignments(value) {
  const allowed = new Set(['available', 'required', 'uninstall', 'exclude']);
  return value.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => {
    // ring | intent | groupName | groupId(object id) | notes
    const [ring, intent = 'required', groupName = '', groupId = '', notes = ''] = line.split('|');
    const normalizedIntent = intent.trim().toLowerCase();
    const name = groupName.trim();
    let groupMode = 'group';
    if (/all\s*devices/i.test(name)) groupMode = 'allDevices';
    else if (/all\s*(licensed\s*)?users/i.test(name)) groupMode = 'allUsers';
    return {
      ring: ring.trim(),
      intent: allowed.has(normalizedIntent) ? normalizedIntent : 'required',
      groupName: name,
      groupId: groupId.trim(),
      groupMode,
      notes: notes.trim()
    };
  });
}

function parseRelationships(value) {
  return value.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => {
    // kind(supersedence|dependency) | targetAppId | mode | targetName
    const [kind = 'supersedence', targetAppId = '', mode = '', targetName = ''] = line.split('|');
    const normalizedKind = kind.trim().toLowerCase() === 'dependency' ? 'dependency' : 'supersedence';
    return { kind: normalizedKind, targetAppId: targetAppId.trim(), mode: mode.trim(), targetName: targetName.trim() };
  }).filter((rel) => rel.targetAppId);
}

function defaultProfile() {
  return {
    id: null,
    name: '',
    appVendor: '',
    appName: '',
    appVersion: '',
    appArch: 'x64',
    appLang: 'EN',
    appRevision: '01',
    toolkitVersion: 'v4',
    templateVersion: 'v4',
    deploymentType: 'Install',
    deployMode: 'Auto',
    requireAdmin: true,
    zeroConfig: false,
    suppressReboot: false,
    closeProcesses: [],
    installTasks: [],
    uiPlan: { welcome: true },
    configPlan: {},
    admxPlan: {},
    visibility: 'personal',
    groupId: null
  };
}

function defaultIntuneDeployment() {
  return {
    id: null,
    name: '',
    profileId: '',
    scriptId: '',
    sourceFolder: '',
    intunewinFile: '',
    appType: 'Windows app (Win32)',
    commandStyle: 'v4',
    installBehavior: 'system',
    restartBehavior: 'return-code',
    uiMode: 'native-v4',
    requirements: {
      architecture: 'x64',
      minOs: 'Windows 10 22H2',
      diskSpaceMb: 0,
      runAs32Bit: false
    },
    installCommand: '',
    uninstallCommand: '',
    detectionType: 'custom-script',
    detectionRule: '',
    returnCodes: [
      { code: 0, type: 'success', meaning: 'Install completed successfully.' },
      { code: 1602, type: 'retry', meaning: 'User deferred or cancelled; let Intune retry.' },
      { code: 3010, type: 'softReboot', meaning: 'Install completed and a reboot is required.' },
      { code: 60008, type: 'failed', meaning: 'PSADT initialization failure.' }
    ],
    assignments: [
      { ring: 'Pilot', intent: 'available', groupName: '', groupId: '', notes: 'Validation ring before broad assignment.' }
    ],
    relationships: [],
    status: 'draft',
    autoPromoteAfterHours: 0,
    autoPromoteRing: '',
    autoPromoteIntent: 'required',
    graphAppId: '',
    graphConnectionId: '',
    notes: '',
    visibility: 'personal',
    groupId: ''
  };
}

function defaultGraphConnection() {
  return {
    id: null,
    name: '',
    tenantId: '',
    clientId: '',
    clientSecret: '',
    cloud: 'global',
    graphBaseUrl: 'https://graph.microsoft.com',
    authorityHost: 'https://login.microsoftonline.com',
    defaultApiVersion: 'v1.0',
    enabled: true,
    visibility: 'personal',
    groupId: ''
  };
}

function noop() {}
</script>
