<script>
  import { AlertTriangle, Loader2, Plus, RefreshCw } from 'lucide-svelte';
  import { resolve } from '$app/paths';
import { fetchRules, unlinkTestFromRule } from '$lib/api/rule.js';
  import { success as toastSuccess, error as toastError } from '$lib/utils/toast.js';
  import RuleEditorModal from '../modals/RuleEditorModal.svelte';

  let { formData = $bindable(), isDirty = $bindable(false) } = $props();

  let rules = $state([]);
  let loading = $state(false);
  let editorOpen = $state(false);
  let editorMode = $state('create');
  let selectedRule = $state(null);
  let lastLoadedTestId = $state(null);

  const hasTestId = $derived.by(() => formData.TestSiteID !== null && formData.TestSiteID !== undefined);
  const rulesCount = $derived.by(() => rules.length);

  function normalizeRulesListResponse(response) {
    if (Array.isArray(response?.data?.data)) return response.data.data;
    if (Array.isArray(response?.data)) return response.data;
    if (Array.isArray(response?.data?.rules)) return response.data.rules;
    return [];
  }

  $effect(() => {
    if (!hasTestId) {
      rules = [];
      lastLoadedTestId = null;
      return;
    }
    loadRules();
  });

  async function loadRules(force = false) {
    if (!hasTestId) return;
      const testId = formData.TestSiteID;
      if (!force && lastLoadedTestId === testId) return;

      loading = true;
      try {
        const response = await fetchRules({ TestSiteID: testId });
        rules = normalizeRulesListResponse(response).filter(Boolean);
        lastLoadedTestId = testId;
    } catch (err) {
      toastError(err?.message || 'Unable to load rules for this test');
      rules = [];
    } finally {
      loading = false;
    }
  }

  function openEditor(mode = 'create', rule = null) {
    editorMode = mode;
    selectedRule = rule;
    editorOpen = true;
  }

  function handleEditorSaved() {
    isDirty = true;
    handleEditorClose();
    loadRules(true);
  }

  function handleEditorClose() {
    editorOpen = false;
    selectedRule = null;
  }

  async function handleUnlink(rule) {
    if (!hasTestId) return;
    if (!confirm('Unlinking removes this rule from the current test only. Continue?')) {
      return;
    }

    try {
      await unlinkTestFromRule(rule.RuleID, formData.TestSiteID);
      toastSuccess('Rule unlinked from test');
      isDirty = true;
      loadRules(true);
    } catch (err) {
      toastError(err?.message || 'Failed to unlink rule');
    }
  }
</script>

<div class="space-y-4">
  <div class="flex items-center justify-between gap-3">
    <div>
      <h2 class="text-lg font-semibold text-gray-800">Rules</h2>
      <p class="text-sm text-gray-500">Attach DSL-powered rules to this test. One test can have multiple rules.</p>
    </div>
    <div class="flex items-center gap-2">
      <span class="badge badge-sm badge-ghost">{rulesCount} linked</span>
      <button
        class="btn btn-sm btn-primary"
        onclick={() => openEditor('create')}
        disabled={!hasTestId || loading}
        type="button"
      >
        <Plus class="w-3.5 h-3.5" />
        New rule
      </button>
    </div>
  </div>

  {#if !hasTestId}
    <div class="alert alert-info">
      <AlertTriangle class="w-4 h-4" />
      Save the test first so we can link rules via `TestSiteID`.
    </div>
  {:else}
    <div class="flex items-center gap-2 text-xs text-gray-500">
      <RefreshCw class="w-4 h-4" />
      <button class="underline" onclick={() => loadRules(true)} type="button">Refresh rules</button>
    </div>

    <div class="bg-base-100 border border-base-200 rounded-lg shadow-sm overflow-hidden">
      {#if loading}
        <div class="p-6 text-center text-sm text-gray-600">
          <Loader2 class="w-6 h-6 mx-auto mb-2 animate-spin" />
          Loading linked rules...
        </div>
      {:else if rules.length === 0}
        <div class="p-6 text-sm text-gray-500 text-center">
          No rules are linked yet. Create one to run custom logic <br /> when events fire.
        </div>
      {:else}
        <div class="divide-y divide-base-200">
          {#each rules as rule (rule.RuleID)}
            <div class="flex flex-col gap-2 px-4 py-3">
              <div class="flex items-center justify-between gap-3">
                <div>
                  <div class="text-xs text-gray-400 uppercase">{rule.EventCode || 'ORDER_CREATED'}</div>
                  <div class="text-sm font-semibold text-gray-800">{rule.RuleCode || 'UNTITLED'}</div>
                  <div class="text-xs text-gray-500">{rule.RuleName || 'Unnamed rule'}</div>
                </div>
                <div class="flex items-center gap-1 text-[10px] text-gray-500">
                  <span class="badge badge-xs {rule.ConditionExprCompiled ? 'badge-success' : 'badge-warning'}">
                    {rule.ConditionExprCompiled ? 'Compiled' : 'Needs compile'}
                  </span>
                </div>
              </div>
              <div class="flex flex-col gap-2 text-xs text-gray-600">
                <p class="truncate">{rule.ConditionExpr || 'No expression defined'}</p>
                <div class="flex gap-2">
                  <button class="btn btn-ghost btn-xs" onclick={() => openEditor('edit', rule)} type="button">Edit</button>
                  <button class="btn btn-ghost btn-xs text-error" onclick={() => handleUnlink(rule)} type="button">Unlink</button>
                </div>
              </div>
            </div>
          {/each}
        </div>
      {/if}
    </div>
  {/if}

    <div class="bg-base-50 border border-dashed border-base-200 rounded-lg p-4 text-xs text-gray-500">
      <p class="font-semibold text-gray-600">Rule engine reference</p>
      <p class="mt-1">Rules run when `test_created` or `result_updated` fire. The DSL uses <code>if(condition; then; else)</code> syntax – see <a href={resolve('/docs/test-rule-engine.md')} class="text-primary underline">docs/test-rule-engine.md</a>.</p>
    </div>

  <RuleEditorModal
    bind:open={editorOpen}
    ruleMode={editorMode}
    testSiteId={formData.TestSiteID}
    initialRule={selectedRule}
    on:saved={handleEditorSaved}
    on:close={handleEditorClose}
  />
</div>
