<script>
import { onMount } from 'svelte';
import { Info, Settings, Calculator, Users, Link, Hash, Type, AlertTriangle, FileText } from 'lucide-svelte';
import { fetchTest, createTest, updateTest, validateTestCode, validateTestName } from '$lib/api/tests.js';
import { success as toastSuccess, error as toastError } from '$lib/utils/toast.js';
import Modal from '$lib/components/Modal.svelte';
import BasicInfoTab from './tabs/BasicInfoTab.svelte';
import TechDetailsTab from './tabs/TechDetailsTab.svelte';
import CalcDetailsTab from './tabs/CalcDetailsTab.svelte';
import GroupMembersTab from './tabs/GroupMembersTab.svelte';
import MappingsTab from './tabs/MappingsTab.svelte';
import RefNumTab from './tabs/RefNumTab.svelte';
import RefTxtTab from './tabs/RefTxtTab.svelte';
import ThresholdTab from './tabs/ThresholdTab.svelte';
import RulesTab from './tabs/RulesTab.svelte';

  let { open = $bindable(false), mode = 'create', testId = null, initialTestType = 'TEST', disciplines = [], departments = [], tests = [], onsave = null } = $props();

  let currentTab = $state('basic');
  let loading = $state(false);
  let saving = $state(false);
  let isDirty = $state(false);
  let validationErrors = $state({});
  let lastLoadedTestId = $state(null);

  // Reference to BasicInfoTab for validation
  let basicInfoTabRef = $state(null);

  // Initialize form state with proper defaults
  let formData = $state(getDefaultFormData());

  const tabConfig = [
    { id: 'basic', label: 'Basic Info', component: Info },
    { id: 'tech', label: 'Tech Details', component: Settings },
    { id: 'calc', label: 'Calculations', component: Calculator },
    { id: 'group', label: 'Group Members', component: Users },
    { id: 'mappings', label: 'Mappings', component: Link },
    { id: 'refnum', label: 'Num Refs', component: Hash },
    { id: 'threshold', label: 'Thresholds', component: AlertTriangle },
    { id: 'reftxt', label: 'Txt Refs', component: Type },
    { id: 'rules', label: 'Rules', component: FileText }
  ];

  const visibleTabs = $derived.by(() => {
    const type = formData?.TestType;
    const resultType = formData?.details?.ResultType;
    const refType = formData?.details?.RefType;
    
    return tabConfig.filter(tab => {
      if (tab.id === 'basic' || tab.id === 'mappings') return true;
      if (tab.id === 'tech') return ['TEST', 'PARAM', 'CALC'].includes(type);
      if (tab.id === 'calc') return type === 'CALC';
      if (tab.id === 'group') return type === 'GROUP';
      if (tab.id === 'refnum') {
        // Show for TEST/PARAM with numeric result types and RANGE ref type
        return ['TEST', 'PARAM'].includes(type) && ['NMRIC', 'RANGE'].includes(resultType) && refType === 'RANGE';
      }
      if (tab.id === 'threshold') {
        // Show for TEST/PARAM with numeric result types and THOLD ref type
        return ['TEST', 'PARAM'].includes(type) && ['NMRIC', 'RANGE'].includes(resultType) && refType === 'THOLD';
      }
      if (tab.id === 'reftxt') {
        // Show for TEST/PARAM with TEXT result type
        return ['TEST', 'PARAM'].includes(type) && resultType === 'TEXT' && refType === 'TEXT';
      }
      if (tab.id === 'rules') {
        return true;
      }
      return false;
    });
  });

  // Computed validation state
  const canSave = $derived.by(() => {
    const codeResult = validateTestCode(formData.TestSiteCode);
    const nameResult = validateTestName(formData.TestSiteName);
    return codeResult.valid && nameResult.valid && formData.TestType !== '';
  });

  const formErrors = $derived.by(() => {
    const errors = [];
    const codeResult = validateTestCode(formData.TestSiteCode);
    if (!codeResult.valid) errors.push(codeResult.error);
    const nameResult = validateTestName(formData.TestSiteName);
    if (!nameResult.valid) errors.push(nameResult.error);
    return errors;
  });

  // Watch for modal open changes and load data
  $effect(() => {
    if (open && mode === 'edit' && testId && testId !== lastLoadedTestId) {
      loadTest();
    } else if (open && mode === 'create' && lastLoadedTestId !== null) {
      resetForm();
    }
  });

  onMount(() => {
    if (open) {
      if (mode === 'edit' && testId) {
        loadTest();
      } else {
        resetForm();
      }
    }
  });

  function getDefaultFormData() {
    return {
      TestSiteID: null,
      TestSiteCode: '',
      TestSiteName: '',
      TestType: initialTestType,
      Description: '',
      SiteID: 1,
      SeqScr: 0,
      SeqRpt: 0,
      VisibleScr: true,
      VisibleRpt: true,
      CountStat: true,
      Requestable: true,
      details: {
        DisciplineID: null,
        DepartmentID: null,
        ResultType: '',
        RefType: '',
        VSet: '',
        Unit1: '',
        Factor: null,
        Unit2: '',
        Decimal: 2,
        ReqQty: null,
        ReqQtyUnit: '',
        CollReq: '',
        Method: '',
        ExpectedTAT: null,
        FormulaCode: '',
        members: []
      },
      refnum: [],
      reftxt: [],
      testmap: []
    };
  }

  function resetForm() {
    formData = getDefaultFormData();
    currentTab = 'basic';
    isDirty = false;
    validationErrors = {};
    lastLoadedTestId = null;
    setDefaults();
  }

  async function loadTest() {
    if (!testId || testId === lastLoadedTestId) return;
    
    loading = true;
    try {
      const response = await fetchTest(testId);
      const test = response.data;
      
      // Transform API data to form state
      formData = {
        TestSiteID: test.TestSiteID,
        TestSiteCode: test.TestSiteCode || '',
        TestSiteName: test.TestSiteName || '',
        TestType: test.TestType || 'TEST',
        Description: test.Description || '',
        SiteID: test.SiteID || 1,
        SeqScr: test.SeqScr || 0,
        SeqRpt: test.SeqRpt || 0,
        VisibleScr: test.VisibleScr === '1' || test.VisibleScr === 1 || test.VisibleScr === true,
        VisibleRpt: test.VisibleRpt === '1' || test.VisibleRpt === 1 || test.VisibleRpt === true,
        CountStat: test.CountStat === '1' || test.CountStat === 1 || test.CountStat === true,
        Requestable: test.Requestable === '1' || test.Requestable === 1 || test.Requestable === true,
        details: {
          DisciplineID: test.DisciplineID || null,
          DepartmentID: test.DepartmentID || null,
          ResultType: test.ResultType || '',
          RefType: test.RefType || '',
          VSet: test.VSet || '',
          Unit1: test.Unit1 || '',
          Factor: test.Factor || null,
          Unit2: test.Unit2 || '',
          Decimal: test.Decimal || 2,
          ReqQty: test.ReqQty || null,
          ReqQtyUnit: test.ReqQtyUnit || '',
          CollReq: test.CollReq || '',
          Method: test.Method || '',
          ExpectedTAT: test.ExpectedTAT || null,
          FormulaCode: test.testdefcal?.[0]?.FormulaCode || test.FormulaCode || '',
          members: test.testdefgrp?.map(m => ({
            TestSiteID: m.TestSiteID,
            TestSiteCode: m.TestSiteCode,
            TestSiteName: m.TestSiteName,
            TestType: m.TestType,
            TestTypeLabel: m.TestTypeLabel,
            SeqScr: m.SeqScr,
            SeqRpt: m.SeqRpt,
            Member: parseInt(m.Member || m.SeqScr || 0)
          })) || []
        },
        refnum: test.refnum || [],
        reftxt: test.reftxt || [],
        testmap: test.testmap || []
      };
      
      // Set defaults for CALC tests
      if (formData.TestType === 'CALC') {
        formData.details.ResultType = 'NMRIC';
        formData.details.RefType = 'RANGE';
      }
      
      lastLoadedTestId = testId;
      currentTab = 'basic';
      isDirty = false;
    } catch (err) {
      toastError(err.message || 'Failed to load test');
    } finally {
      loading = false;
    }
  }

  function setDefaults() {
    const type = formData.TestType;
    if (type === 'CALC') {
      formData.details.ResultType = 'NMRIC';
      formData.details.RefType = 'RANGE';
    } else if (type === 'GROUP' || type === 'TITLE') {
      formData.details.ResultType = 'NORES';
      formData.details.RefType = 'NOREF';
    } else {
      formData.details.ResultType = '';
      formData.details.RefType = '';
    }
  }

  function handleTabChange(tabId) {
    currentTab = tabId;
  }

  function handleTypeChange(newType) {
    if (isDirty && !confirm('Changing test type will reset some fields. Continue?')) {
      return;
    }
    formData.TestType = newType;
    setDefaults();
    isDirty = false;
  }

  /**
   * Validate the entire form
   * @returns {boolean}
   */
  function validateForm() {
    const errors = {};

    // Validate basic info
    const codeResult = validateTestCode(formData.TestSiteCode);
    if (!codeResult.valid) errors.TestSiteCode = codeResult.error;

    const nameResult = validateTestName(formData.TestSiteName);
    if (!nameResult.valid) errors.TestSiteName = nameResult.error;

    if (!formData.TestType) {
      errors.TestType = 'Test type is required';
    }

    if (formData.TestType === 'CALC') {
      const formulaCode = formData?.details?.FormulaCode || '';
      const membersFromTestDefGrp = Array.isArray(formData?.testdefgrp) ? formData.testdefgrp : [];
      const membersFromDetails = Array.isArray(formData?.details?.members) ? formData.details.members : [];

      const seenCodes = [];
      const selectedMembers = [];
      [...membersFromTestDefGrp, ...membersFromDetails].forEach((member) => {
        const code = member?.TestSiteCode;
        if (code && !seenCodes.includes(code)) {
          seenCodes.push(code);
          selectedMembers.push(member);
        }
      });
      if (selectedMembers.length === 0) {
        errors.members = 'At least one member is required for CALC tests';
      }

      const braceRefs = formulaCode.match(/\{[^{}]+\}/g) || [];
      if (braceRefs.length === 0) {
        errors.FormulaCode = 'Formula must include at least one member reference like {CODE}';
      } else {
        const missingMemberCodes = selectedMembers
          .map((member) => member.TestSiteCode)
          .filter((code) => !formulaCode.includes(`{${code}}`));

        if (missingMemberCodes.length > 0) {
          const formattedMissing = missingMemberCodes.map((code) => `{${code}}`).join(', ');
          errors.FormulaCode = `Formula must reference all members: ${formattedMissing}`;
        }
      }
    }

    validationErrors = errors;
    return Object.keys(errors).length === 0;
  }

  async function handleSave() {
    if (!validateForm()) {
      toastError('Please fix validation errors');
      if (validationErrors.FormulaCode || validationErrors.members) {
        currentTab = 'calc';
      } else {
        currentTab = 'basic';
      }
      return;
    }

    saving = true;
    try {
      if (mode === 'create') {
        await createTest(formData);
        toastSuccess('Test created successfully');
      } else {
        await updateTest(formData);
        toastSuccess('Test updated successfully');
      }
      
      if (onsave) onsave();
      open = false;
      resetForm();
    } catch (err) {
      toastError(err.message || 'Failed to save test');
    } finally {
      saving = false;
    }
  }

  function handleClose() {
    if (isDirty && !confirm('You have unsaved changes. Discard?')) {
      return;
    }
    open = false;
    resetForm();
  }
</script>

<Modal bind:open size="wide" title={mode === 'create' ? 'New Test' : 'Edit Test'}>
  {#if loading}
    <div class="flex items-center justify-center py-16">
      <span class="loading loading-spinner loading-lg text-primary"></span>
    </div>
  {:else}
    {#if formErrors.length > 0}
      <div class="alert alert-warning alert-sm mb-4">
        <svg xmlns="http://www.w3.org/2000/svg" class="stroke-current shrink-0 h-4 w-4" fill="none" viewBox="0 0 24 24">
          <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z" />
        </svg>
        <div>
          <span class="font-semibold">Please fix the following errors:</span>
          <ul class="list-disc list-inside text-sm mt-1">
            {#each formErrors as error, i (`${error}-${i}`)}
              <li>{error}</li>
            {/each}
          </ul>
        </div>
      </div>
    {/if}

    <div class="flex flex-col" style="height: 75vh; max-height: 650px;">
      <!-- Top Tabs -->
      <div class="border-b border-base-200 bg-base-50">
        <div class="flex overflow-x-auto">
          {#each visibleTabs as tab (tab.id)}
            {@const IconComponent = tab.component}
            <button
              class="flex items-center gap-2 px-4 py-3 text-sm font-medium whitespace-nowrap border-b-2 transition-all duration-200"
              class:border-primary={currentTab === tab.id}
              class:text-primary={currentTab === tab.id}
              class:border-transparent={currentTab !== tab.id}
              class:text-gray-600={currentTab !== tab.id}
              class:hover:text-gray-800={currentTab !== tab.id}
              onclick={() => handleTabChange(tab.id)}
              aria-selected={currentTab === tab.id}
              role="tab"
            >
              <IconComponent class="w-4 h-4 flex-shrink-0" />
              <span>{tab.label}</span>
            </button>
          {/each}
        </div>
      </div>

      <!-- Tab Content -->
      <div class="flex-1 overflow-y-auto p-6">
        {#if currentTab === 'basic'}
          <BasicInfoTab
            bind:this={basicInfoTabRef}
            bind:formData
            bind:isDirty
            onTypeChange={handleTypeChange}
            {mode}
          />
        {:else if currentTab === 'tech'}
          <TechDetailsTab
            bind:formData
            {disciplines}
            {departments}
            bind:isDirty
            onSwitchTab={handleTabChange}
          />
        {:else if currentTab === 'calc'}
          <CalcDetailsTab
            bind:formData
            {tests}
            bind:isDirty
            {validationErrors}
          />
        {:else if currentTab === 'group'}
          <GroupMembersTab
            bind:formData
            {tests}
            bind:isDirty
          />
        {:else if currentTab === 'mappings'}
          <MappingsTab
            bind:formData
            bind:isDirty
            testCode={formData.TestSiteCode}
          />
        {:else if currentTab === 'refnum'}
          <RefNumTab
            bind:formData
            bind:isDirty
          />
        {:else if currentTab === 'threshold'}
          <ThresholdTab
            bind:formData
            bind:isDirty
          />
        {:else if currentTab === 'reftxt'}
          <RefTxtTab
            bind:formData
            bind:isDirty
          />
        {:else if currentTab === 'rules'}
          <RulesTab
            bind:formData
            bind:isDirty
            {mode}
          />
        {/if}
      </div>
    </div>

  {/if}

  {#snippet footer()}
    <button class="btn btn-ghost" onclick={handleClose} type="button" disabled={saving || loading}>Cancel</button>
    <button class="btn btn-primary" onclick={handleSave} disabled={saving || loading || !canSave} type="button">
      {#if saving}
        <span class="loading loading-spinner loading-sm mr-2"></span>
      {/if}
      {saving ? 'Saving...' : 'Save'}
    </button>
  {/snippet}
</Modal>
