<script setup lang="ts">
import { computed, reactive, ref } from "vue";
import { adminSecretsAPI } from "@/api";
import type { AdminSecretsPlanRequest, AdminSecretsPlanResponse } from "@/types";
import type { AdminSecretsStoreView, AdminSecretsSummaryView } from "@/stores/admin-secrets-view";

const props = defineProps<{
  summary: AdminSecretsSummaryView;
}>();

interface PlanForm {
  mode: "create" | "edit";
  externalSecretName: string;
  targetSecretName: string;
  storeKind: "ClusterSecretStore" | "SecretStore";
  storeName: string;
  storeNamespace: string;
  remotePath: string;
  property: string;
  version: string;
  targetKey: string;
  refreshInterval: string;
  consumerRolloutEnabled: boolean;
  consumerRolloutIntent: string;
}

const defaultStore = computed(() => props.summary.stores[0] ?? { kind: "ClusterSecretStore", name: "hwlab-secret-plane-vault-cluster", namespace: props.summary.target.infraNamespace, scope: "cluster", status: "Unknown", reason: "" });
const form = reactive<PlanForm>({
  mode: "create",
  externalSecretName: "",
  targetSecretName: "",
  storeKind: defaultStore.value.kind === "SecretStore" ? "SecretStore" : "ClusterSecretStore",
  storeName: defaultStore.value.name,
  storeNamespace: defaultStore.value.kind === "SecretStore" ? props.summary.target.runtimeNamespace : defaultStore.value.namespace,
  remotePath: "hwlab-secret-plane/example",
  property: "password",
  version: "",
  targetKey: "password",
  refreshInterval: "1m",
  consumerRolloutEnabled: true,
  consumerRolloutIntent: "rollout-marker"
});

const attempted = ref(false);
const planning = ref(false);
const planResult = ref<AdminSecretsPlanResponse | null>(null);
const planError = ref<string | null>(null);

const storeOptions = computed<AdminSecretsStoreView[]>(() => props.summary.stores);
const fieldErrors = computed(() => {
  const errors: Record<string, string> = {};
  if (!safeName(form.externalSecretName)) errors.externalSecretName = "需要 DNS label 格式的 ExternalSecret 名称。";
  const targetSecret = form.targetSecretName.trim() || form.externalSecretName.trim();
  if (!safeName(targetSecret)) errors.targetSecretName = "需要 DNS label 格式的 target Secret 名称。";
  if (!form.storeName.trim()) errors.storeName = "需要选择或填写 Store 名称。";
  if (form.storeKind === "SecretStore" && form.storeNamespace.trim() !== props.summary.target.runtimeNamespace) errors.storeNamespace = "SecretStore 只能使用目标 namespace。";
  if (!/^[A-Za-z0-9._/-]+$/u.test(form.remotePath.trim())) errors.remotePath = "需要 sourceRef path。";
  if (!/^[A-Za-z0-9._-]+$/u.test(form.property.trim())) errors.property = "需要 sourceRef property。";
  if (!/^[A-Za-z0-9._-]+$/u.test(form.targetKey.trim())) errors.targetKey = "需要 target key。";
  if (!/^\d+[smhd]$/u.test(form.refreshInterval.trim())) errors.refreshInterval = "refresh interval 需要使用 s/m/h/d 后缀。";
  return errors;
});
const validationMessages = computed(() => Object.values(fieldErrors.value));
const resultPlan = computed(() => planResult.value?.plan ?? null);
const resultData = computed(() => Array.isArray(resultPlan.value?.data) ? resultPlan.value.data : []);
const resultConsumers = computed(() => Array.isArray(resultPlan.value?.affectedConsumers) ? resultPlan.value.affectedConsumers : []);
const resultChecks = computed(() => Array.isArray(planResult.value?.checks) ? planResult.value.checks : []);
const resultRisks = computed(() => Array.isArray(planResult.value?.risks) ? planResult.value.risks : []);
const resultTone = computed(() => planResult.value?.ok === false ? "failed" : planResult.value?.status === "planned" ? "ready" : "pending");
const statusLabel = computed(() => {
  if (!planResult.value) return "not submitted";
  if (planResult.value.ok === false) return `failed: ${planResult.value.failureKind ?? "unknown"}`;
  return `${planResult.value.status ?? "planned"} / dry-run`;
});

function safeName(value: string): boolean {
  const name = value.trim();
  return /^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/u.test(name) && name.length <= 63;
}

function syncStoreDefaults(): void {
  const match = storeOptions.value.find((store) => store.kind === form.storeKind) ?? null;
  form.storeName = match?.name || form.storeName;
  form.storeNamespace = form.storeKind === "SecretStore" ? props.summary.target.runtimeNamespace : match?.namespace || props.summary.target.infraNamespace;
}

async function submitPlan(): Promise<void> {
  attempted.value = true;
  planError.value = null;
  if (validationMessages.value.length > 0) return;
  planning.value = true;
  const response = await adminSecretsAPI.plan(buildPayload());
  planResult.value = response.data;
  if (!response.ok) planError.value = response.error ?? `HTTP ${response.status}`;
  planning.value = false;
}

function buildPayload(): AdminSecretsPlanRequest {
  return {
    mode: form.mode,
    target: {
      node: props.summary.target.node,
      lane: props.summary.target.lane,
      namespace: props.summary.target.runtimeNamespace
    },
    externalSecretName: form.externalSecretName.trim(),
    targetSecretName: form.targetSecretName.trim() || form.externalSecretName.trim(),
    store: {
      kind: form.storeKind,
      name: form.storeName.trim(),
      namespace: form.storeNamespace.trim()
    },
    data: [{
      targetKey: form.targetKey.trim(),
      sourceRef: {
        path: form.remotePath.trim(),
        property: form.property.trim(),
        version: form.version.trim() || null
      }
    }],
    refreshInterval: form.refreshInterval.trim(),
    consumerRollout: {
      enabled: form.consumerRolloutEnabled,
      intent: form.consumerRolloutEnabled ? form.consumerRolloutIntent.trim() || "rollout-marker" : "none"
    }
  };
}
</script>

<template>
  <section class="data-panel admin-crud-panel secrets-plan-panel" data-testid="admin-secrets-plan-panel">
    <header class="panel-header">
      <div>
        <h2>ExternalSecret Plan</h2>
        <small>{{ props.summary.target.node }} / {{ props.summary.target.lane }} / {{ props.summary.target.runtimeNamespace }}</small>
      </div>
      <span class="status-pill" data-status="dry-run">dry-run only</span>
    </header>

    <ol class="secrets-plan-steps" aria-label="ExternalSecret plan steps">
      <li><strong>1</strong><span>Target</span></li>
      <li><strong>2</strong><span>Names</span></li>
      <li><strong>3</strong><span>Store</span></li>
      <li><strong>4</strong><span>SourceRef</span></li>
      <li><strong>5</strong><span>Result</span></li>
    </ol>

    <form class="admin-form secrets-plan-form" @submit.prevent="submitPlan">
      <fieldset class="secrets-plan-fieldset">
        <legend>Target</legend>
        <label>node<input :value="props.summary.target.node" readonly data-testid="plan-node" /></label>
        <label>lane<input :value="props.summary.target.lane" readonly data-testid="plan-lane" /></label>
        <label>namespace<input :value="props.summary.target.runtimeNamespace" readonly data-testid="plan-namespace" /></label>
        <label>mode
          <select v-model="form.mode" data-testid="plan-mode">
            <option value="create">create</option>
            <option value="edit">edit</option>
          </select>
        </label>
      </fieldset>

      <fieldset class="secrets-plan-fieldset">
        <legend>Names</legend>
        <label>ExternalSecret
          <input v-model.trim="form.externalSecretName" placeholder="example-secret" autocomplete="off" data-testid="plan-external-secret-name" />
        </label>
        <label>target Secret
          <input v-model.trim="form.targetSecretName" placeholder="defaults to ExternalSecret" autocomplete="off" data-testid="plan-target-secret-name" />
        </label>
      </fieldset>

      <fieldset class="secrets-plan-fieldset">
        <legend>Store</legend>
        <label>kind
          <select v-model="form.storeKind" data-testid="plan-store-kind" @change="syncStoreDefaults">
            <option value="ClusterSecretStore">ClusterSecretStore</option>
            <option value="SecretStore">SecretStore</option>
          </select>
        </label>
        <label>name
          <input v-model.trim="form.storeName" list="admin-secrets-store-options" autocomplete="off" data-testid="plan-store-name" />
          <datalist id="admin-secrets-store-options">
            <option v-for="store in storeOptions" :key="`${store.kind}:${store.name}`" :value="store.name">{{ store.kind }}</option>
          </datalist>
        </label>
        <label>store namespace
          <input v-model.trim="form.storeNamespace" :readonly="form.storeKind === 'ClusterSecretStore'" autocomplete="off" data-testid="plan-store-namespace" />
        </label>
        <p class="secrets-plan-note span-2">SecretStore must stay in target namespace; ClusterSecretStore plans against the selected target namespace.</p>
      </fieldset>

      <fieldset class="secrets-plan-fieldset">
        <legend>SourceRef</legend>
        <label>path
          <input v-model.trim="form.remotePath" autocomplete="off" data-testid="plan-remote-path" />
        </label>
        <label>property
          <input v-model.trim="form.property" autocomplete="off" data-testid="plan-remote-property" />
        </label>
        <label>version
          <input v-model.trim="form.version" placeholder="optional" autocomplete="off" data-testid="plan-remote-version" />
        </label>
        <label>target key
          <input v-model.trim="form.targetKey" autocomplete="off" data-testid="plan-target-key" />
        </label>
        <label>refresh interval
          <input v-model.trim="form.refreshInterval" autocomplete="off" data-testid="plan-refresh-interval" />
        </label>
        <label class="secrets-plan-toggle">
          <input v-model="form.consumerRolloutEnabled" type="checkbox" data-testid="plan-consumer-rollout" />
          <span>consumer rollout marker</span>
        </label>
        <label class="span-2">rollout intent
          <input v-model.trim="form.consumerRolloutIntent" :disabled="!form.consumerRolloutEnabled" autocomplete="off" data-testid="plan-consumer-rollout-intent" />
        </label>
      </fieldset>

      <section v-if="attempted && validationMessages.length > 0" class="form-error" data-testid="admin-secrets-plan-validation">
        <strong>字段校验未通过</strong>
        <ul>
          <li v-for="message in validationMessages" :key="message">{{ message }}</li>
        </ul>
      </section>

      <div class="table-actions-inline">
        <button class="table-action" type="submit" :disabled="planning" data-testid="admin-secrets-plan-submit">{{ planning ? "Planning" : "Plan" }}</button>
        <span class="status-pill" data-status="dry-run">valuesPrinted=false</span>
        <span class="status-pill" data-status="dry-run">secretMaterialStored=false</span>
      </div>
    </form>

    <section v-if="planError" class="form-error" data-testid="admin-secrets-plan-error">{{ planError }}</section>

    <section v-if="planResult" class="secrets-plan-result" data-testid="admin-secrets-plan-result">
      <header class="panel-header">
        <div>
          <h3>Plan Result</h3>
          <small>{{ planResult.planId || "no plan id" }}</small>
        </div>
        <span class="status-pill" :data-status="resultTone" data-testid="admin-secrets-plan-status">{{ statusLabel }}</span>
      </header>

      <dl class="secrets-fact-grid">
        <div><dt>valuesPrinted</dt><dd>{{ String(planResult.valuesPrinted) }}</dd></div>
        <div><dt>secretMaterialStored</dt><dd>{{ String(planResult.secretMaterialStored) }}</dd></div>
        <div><dt>permission</dt><dd>{{ planResult.permission?.id }} / {{ String(planResult.permission?.allowed) }}</dd></div>
        <div><dt>operation</dt><dd>{{ resultPlan?.operation || "-" }}</dd></div>
        <div><dt>target</dt><dd>{{ resultPlan?.target?.node }} / {{ resultPlan?.target?.lane }} / {{ resultPlan?.target?.namespace }}</dd></div>
        <div><dt>store</dt><dd>{{ resultPlan?.store?.kind }} / {{ resultPlan?.store?.name }}</dd></div>
      </dl>

      <section class="secrets-subsection">
        <h3>Mapping</h3>
        <div class="secrets-chip-list">
          <span v-for="item in resultData" :key="`${item.targetKey}:${item.referenceFingerprint}`" class="secrets-chip">
            <strong>{{ item.targetKey }} / {{ item.presence }}</strong>
            <small>{{ item.sourceRef?.path }} / {{ item.sourceRef?.property }} / {{ item.sourceRef?.version || "latest" }} / {{ item.referenceFingerprint }}</small>
          </span>
        </div>
      </section>

      <section class="secrets-plan-result-grid">
        <section class="secrets-subsection">
          <h3>Consumers</h3>
          <div class="secrets-chip-list">
            <span v-if="resultConsumers.length === 0" class="secrets-chip"><strong>none</strong><small>{{ resultPlan?.consumerRollout?.marker || "none" }}</small></span>
            <span v-for="consumer in resultConsumers" :key="`${consumer.serviceId}:${consumer.envName}`" class="secrets-chip">
              <strong>{{ consumer.serviceId }}</strong>
              <small>{{ consumer.kind }} / {{ consumer.injectAs }} / {{ consumer.rollout }}</small>
            </span>
          </div>
        </section>

        <section class="secrets-subsection">
          <h3>Risks</h3>
          <div class="secrets-chip-list">
            <span v-for="risk in resultRisks" :key="`${risk.code}:${risk.severity}`" class="secrets-chip">
              <strong>{{ risk.code }} / {{ risk.severity }}</strong>
              <small>{{ risk.message }}</small>
            </span>
          </div>
        </section>
      </section>

      <section class="secrets-subsection">
        <h3>Checks</h3>
        <div class="secrets-plan-checks">
          <span v-for="check in resultChecks" :key="check.id" class="status-pill" :data-status="check.status === 'failed' ? 'failed' : 'ready'" :title="check.detail">
            {{ check.label }}: {{ check.status }}
          </span>
        </div>
      </section>
    </section>
  </section>
</template>
