<script>
  import { onMount } from 'svelte';
  import { Plus, Edit2, Trash2, Link } from 'lucide-svelte';
  import Modal from '$lib/components/Modal.svelte';
  import { get } from '$lib/api/client.js';
  import { error as toastError } from '$lib/utils/toast.js';

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

  let modalOpen = $state(false);
  let modalMode = $state('create');
  let selectedMapping = $state(null);
  let loading = $state(false);
  let mappingsData = $state([]);
  
  // Dropdown data
  let sites = $state([]);
  let workstations = $state([]);
  let departments = $state([]);
  let equipment = $state([]);
  let containers = $state([]);
  let hostApps = $state([]);
  
  // Cache for names
  let namesCache = $state({
    sites: {},
    workstations: {},
    departments: {},
    equipment: {},
    containers: {},
    hostApps: {}
  });
  
  let editingMapping = $state({
    HostType: '',
    HostID: '',
    HostTestCode: '',
    HostTestName: '',
    ClientType: '',
    ClientID: '',
    ConDefID: '',
    ClientTestCode: '',
    ClientTestName: ''
  });

  const hostTypes = ['HIS', 'SITE', 'WST', 'INST'];
  const clientTypes = ['HIS', 'SITE', 'WST', 'INST'];

  // Fetch mappings when testCode changes
  $effect(() => {
    if (testCode) {
      fetchMappings();
    }
  });

  onMount(() => {
    if (testCode) {
      fetchMappings();
    }
    // Load dropdown data
    loadDropdownData();
  });

  async function loadDropdownData() {
    try {
      // Load sites
      const sitesRes = await get('/api/organization/site');
      if (sitesRes.status === 'success' && sitesRes.data) {
        sites = sitesRes.data;
        sites.forEach(s => namesCache.sites[s.SiteID] = s.SiteName);
      }
      
      // Load workstations
      const wstRes = await get('/api/organization/workstation');
      if (wstRes.status === 'success' && wstRes.data) {
        workstations = wstRes.data;
        workstations.forEach(w => namesCache.workstations[w.WorkstationID] = w.WorkstationName);
      }
      
      // Load departments
      const deptRes = await get('/api/organization/department');
      if (deptRes.status === 'success' && deptRes.data) {
        departments = deptRes.data;
        departments.forEach(d => namesCache.departments[d.DepartmentID] = d.DeptName);
      }
      
      // Load equipment
      const equipRes = await get('/api/equipmentlist');
      if (equipRes.status === 'success' && equipRes.data) {
        equipment = equipRes.data;
        equipment.forEach(e => namesCache.equipment[e.EID] = e.InstrumentName || e.IEID);
      }
      
      // Load containers
      const contRes = await get('/api/specimen/container');
      if (contRes.status === 'success' && contRes.data) {
        containers = contRes.data;
        containers.forEach(c => namesCache.containers[c.ConDefID] = c.ConName);
      }
      
      // Load host applications (HIS)
      const hostRes = await get('/api/organization/hostapp');
      if (hostRes.status === 'success' && hostRes.data) {
        hostApps = hostRes.data;
        hostApps.forEach(h => namesCache.hostApps[h.HostAppID] = h.HostAppName);
      }
    } catch (err) {
      console.error('Failed to load dropdown data:', err);
    }
  }

  function getHostOptions() {
    switch (editingMapping.HostType) {
      case 'HIS':
        return hostApps.map(h => ({ value: h.HostAppID, label: h.HostAppName }));
      case 'SITE':
        return sites.map(s => ({ value: s.SiteID, label: s.SiteName }));
      case 'WST':
        return workstations.map(w => ({ value: w.WorkstationID, label: w.WorkstationName }));
      case 'DEPT':
        return departments.map(d => ({ value: d.DepartmentID, label: d.DeptName }));
      case 'INST':
        return equipment.map(e => ({ value: e.EID, label: e.InstrumentName || e.IEID }));
      default:
        return [];
    }
  }

  function getClientOptions() {
    switch (editingMapping.ClientType) {
      case 'HIS':
        return hostApps.map(h => ({ value: h.HostAppID, label: h.HostAppName }));
      case 'SITE':
        return sites.map(s => ({ value: s.SiteID, label: s.SiteName }));
      case 'WST':
        return workstations.map(w => ({ value: w.WorkstationID, label: w.WorkstationName }));
      case 'DEPT':
        return departments.map(d => ({ value: d.DepartmentID, label: d.DeptName }));
      case 'INST':
        return equipment.map(e => ({ value: e.EID, label: e.InstrumentName || e.IEID }));
      default:
        return [];
    }
  }

  async function fetchEntityName(type, id) {
    if (!id) return null;
    
    // Check cache first
    if (type === 'HIS' && namesCache.hostApps[id]) return namesCache.hostApps[id];
    if (type === 'SITE' && namesCache.sites[id]) return namesCache.sites[id];
    if (type === 'WST' && namesCache.workstations[id]) return namesCache.workstations[id];
    if (type === 'DEPT' && namesCache.departments[id]) return namesCache.departments[id];
    if (type === 'INST' && namesCache.equipment[id]) return namesCache.equipment[id];

    try {
      let response;
      switch (type) {
        case 'HIS':
          response = await get(`/api/organization/hostapp/${id}`);
          if (response.status === 'success' && response.data) {
            namesCache.hostApps[id] = response.data.HostAppName || `HIS ${id}`;
            return namesCache.hostApps[id];
          }
          break;
        case 'SITE':
          response = await get(`/api/organization/site/${id}`);
          if (response.status === 'success' && response.data) {
            namesCache.sites[id] = response.data.SiteName || `Site ${id}`;
            return namesCache.sites[id];
          }
          break;
        case 'WST':
          response = await get(`/api/organization/workstation/${id}`);
          if (response.status === 'success' && response.data) {
            namesCache.workstations[id] = response.data.WorkstationName || `Workstation ${id}`;
            return namesCache.workstations[id];
          }
          break;
        case 'DEPT':
          response = await get(`/api/organization/department/${id}`);
          if (response.status === 'success' && response.data) {
            namesCache.departments[id] = response.data.DeptName || `Department ${id}`;
            return namesCache.departments[id];
          }
          break;
        case 'INST':
          response = await get(`/api/equipmentlist/${id}`);
          if (response.status === 'success' && response.data) {
            namesCache.equipment[id] = response.data.InstrumentName || response.data.IEID || `Equipment ${id}`;
            return namesCache.equipment[id];
          }
          break;
      }
    } catch (err) {
      console.error(`Failed to fetch ${type} name for ID ${id}:`, err);
    }
    return `${type} ${id}`;
  }

  async function fetchContainerName(conDefId) {
    if (!conDefId) return null;
    if (namesCache.containers[conDefId]) return namesCache.containers[conDefId];

    try {
      const response = await get(`/api/specimen/container/${conDefId}`);
      if (response.status === 'success' && response.data) {
        namesCache.containers[conDefId] = response.data.ConName || `Container ${conDefId}`;
        return namesCache.containers[conDefId];
      }
    } catch (err) {
      console.error(`Failed to fetch container name for ID ${conDefId}:`, err);
    }
    return `Container ${conDefId}`;
  }

  async function fetchMappingDetails(testMapId) {
    try {
      const response = await get(`/api/test/testmap/detail/by-testmap/${testMapId}`);
      if (response.status === 'success' && response.data && response.data.length > 0) {
        return response.data[0];
      }
    } catch (err) {
      console.error(`Failed to fetch mapping details for TestMapID ${testMapId}:`, err);
    }
    return null;
  }

  async function fetchMappings() {
    if (!testCode) return;
    
    loading = true;
    try {
      const response = await get(`/api/test/testmap/by-testcode/${testCode}`);
      if (response.status === 'success' && response.data) {
        const transformedData = await Promise.all(response.data.map(async item => {
          const [hostName, clientName, details] = await Promise.all([
            fetchEntityName(item.HostType, item.HostID),
            fetchEntityName(item.ClientType, item.ClientID),
            fetchMappingDetails(item.TestMapID)
          ]);
          
          let containerName = null;
          if (details && details.ConDefID) {
            containerName = await fetchContainerName(details.ConDefID);
          }
          
          return {
            TestMapID: item.TestMapID,
            TestSiteID: item.TestSiteID,
            HostType: item.HostType,
            HostID: item.HostID,
            HostName: hostName,
            HostTypeLabel: item.HostTypeLabel,
            ClientType: item.ClientType,
            ClientID: item.ClientID,
            ClientName: clientName,
            ClientTypeLabel: item.ClientTypeLabel,
            ConDefID: details?.ConDefID || null,
            ContainerName: containerName,
            CreateDate: item.CreateDate,
            EndDate: item.EndDate,
            HostTestCode: details?.HostTestCode || '',
            HostTestName: details?.HostTestName || '',
            ClientTestCode: details?.ClientTestCode || '',
            ClientTestName: details?.ClientTestName || ''
          };
        }));
        
        mappingsData = transformedData;
        formData.testmap = [...mappingsData];
      } else {
        mappingsData = [];
        formData.testmap = [];
      }
    } catch (err) {
      toastError(err.message || 'Failed to load mappings');
      mappingsData = [];
      formData.testmap = [];
    } finally {
      loading = false;
    }
  }

  function handleFieldChange() {
    isDirty = true;
  }

  function openAddMapping() {
    modalMode = 'create';
    editingMapping = {
      HostType: '',
      HostID: '',
      HostTestCode: '',
      HostTestName: '',
      ClientType: '',
      ClientID: '',
      ConDefID: '',
      ClientTestCode: '',
      ClientTestName: ''
    };
    modalOpen = true;
  }

  function openEditMapping(mapping) {
    modalMode = 'edit';
    selectedMapping = mapping;
    editingMapping = { ...mapping };
    modalOpen = true;
  }

  function removeMapping(index) {
    const newMappings = mappingsData.filter((_, i) => i !== index);
    mappingsData = newMappings;
    formData.testmap = [...newMappings];
    handleFieldChange();
  }

  function saveMapping() {
    if (modalMode === 'create') {
      const newMapping = { 
        ...editingMapping, 
        TestMapID: `temp-${Date.now()}`
      };
      mappingsData = [...mappingsData, newMapping];
    } else {
      const newMappings = mappingsData.map(m => 
        m === selectedMapping ? { ...editingMapping } : m
      );
      mappingsData = newMappings;
    }
    formData.testmap = [...mappingsData];
    modalOpen = false;
    handleFieldChange();
  }
</script>

<div class="space-y-6">
  <h2 class="text-lg font-semibold text-gray-800">System Mappings</h2>

  <div class="alert alert-info text-sm">
    <Link class="w-4 h-4" />
    <div>
      <strong>Test Mappings:</strong> Configure how this test maps to external systems (HIS, Lab Information Systems, etc.)
    </div>
  </div>

  <div class="space-y-4">
    <h3 class="text-sm font-medium text-gray-600 uppercase tracking-wide">Current Mappings ({mappingsData?.length || 0})</h3>
    
    {#if loading}
      <div class="flex items-center justify-center py-8">
        <span class="loading loading-spinner loading-md text-primary"></span>
      </div>
    {:else if !mappingsData || mappingsData.length === 0}
      <div class="text-center py-8 bg-base-200 rounded-lg">
        <Link class="w-12 h-12 mx-auto text-gray-400 mb-2" />
        <p class="text-sm text-gray-500">No mappings configured</p>
        <p class="text-xs text-gray-400">Add mappings to external systems</p>
      </div>
    {:else}
      <div class="overflow-x-auto border border-base-200 rounded-lg">
        <table class="table table-sm table-compact">
          <thead>
            <tr class="bg-base-200">
              <th>Host System</th>
              <th>Client System</th>
              <th class="w-24 text-center">Actions</th>
            </tr>
          </thead>
          <tbody>
            {#each mappingsData as mapping, idx (idx)}
              <tr class="hover:bg-base-100">
                <td>
                  <div class="text-sm">
                    <div class="font-medium">{mapping.HostName || mapping.HostTypeLabel || mapping.HostType || '-'}</div>
                    <div class="text-xs text-gray-500">{mapping.HostTypeLabel || mapping.HostType} (ID: {mapping.HostID || '-'})</div>
                  </div>
                </td>
                <td>
                  <div class="text-sm">
                    <div class="font-medium">{mapping.ClientName || mapping.ClientTypeLabel || mapping.ClientType || '-'}</div>
                    <div class="text-xs text-gray-500">
                      {mapping.ClientTypeLabel || mapping.ClientType} (ID: {mapping.ClientID || '-'})
                      {#if mapping.ClientType === 'INST' && mapping.ContainerName}
                        <span class="text-primary"> • {mapping.ContainerName}</span>
                      {/if}
                    </div>
                  </div>
                </td>
                <td>
                  <div class="flex justify-center gap-1">
                    <button
                      class="btn btn-ghost btn-xs"
                      onclick={() => openEditMapping(mapping)}
                      title="Edit Mapping"
                    >
                      <Edit2 class="w-3 h-3" />
                    </button>
                    <button
                      class="btn btn-ghost btn-xs text-error"
                      onclick={() => removeMapping(idx)}
                      title="Remove Mapping"
                    >
                      <Trash2 class="w-3 h-3" />
                    </button>
                  </div>
                </td>
              </tr>
            {/each}
          </tbody>
        </table>
      </div>
    {/if}
  </div>

  <div class="flex justify-end">
    <button class="btn btn-sm btn-primary" onclick={openAddMapping}>
      <Plus class="w-4 h-4 mr-2" />
      Add Mapping
    </button>
  </div>
</div>

<Modal bind:open={modalOpen} title={modalMode === 'create' ? 'Add Mapping' : 'Edit Mapping'} size="lg">
  <div class="space-y-6 max-h-[500px] overflow-y-auto">
    <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
      <div class="space-y-3">
        <h3 class="text-sm font-medium text-gray-600 uppercase tracking-wide border-b pb-2">Host System</h3>
        
        <div class="form-control">
          <label class="label text-sm">Type</label>
          <select 
            class="select select-sm select-bordered" 
            bind:value={editingMapping.HostType}
            disabled={modalMode === 'edit'}
          >
            <option value="">Select type...</option>
            {#each hostTypes as type (type)}
              <option value={type}>{type}</option>
            {/each}
          </select>
        </div>

        <div class="form-control">
          <label class="label text-sm">ID</label>
          {#if modalMode === 'create' && editingMapping.HostType}
            <select class="select select-sm select-bordered" bind:value={editingMapping.HostID}>
              <option value="">Select {editingMapping.HostType}...</option>
              {#each getHostOptions() as option (option.value)}
                <option value={option.value}>{option.label}</option>
              {/each}
            </select>
          {:else if modalMode === 'edit'}
            <input 
              type="text" 
              class="input input-sm input-bordered" 
              value={editingMapping.HostName || `${editingMapping.HostType} ${editingMapping.HostID}`}
              disabled
            />
          {:else}
            <input 
              type="text" 
              class="input input-sm input-bordered" 
              bind:value={editingMapping.HostID} 
              placeholder="System ID"
            />
          {/if}
        </div>

        <div class="form-control">
          <label class="label text-sm">Test Code</label>
          <input type="text" class="input input-sm input-bordered" bind:value={editingMapping.HostTestCode} placeholder="Test code in host system" />
        </div>

        <div class="form-control">
          <label class="label text-sm">Test Name</label>
          <input type="text" class="input input-sm input-bordered" bind:value={editingMapping.HostTestName} placeholder="Test name in host system" />
        </div>
      </div>

      <div class="space-y-3">
        <h3 class="text-sm font-medium text-gray-600 uppercase tracking-wide border-b pb-2">Client System</h3>
        
        <div class="form-control">
          <label class="label text-sm">Type</label>
          <select 
            class="select select-sm select-bordered" 
            bind:value={editingMapping.ClientType}
            disabled={modalMode === 'edit'}
          >
            <option value="">Select type...</option>
            {#each clientTypes as type (type)}
              <option value={type}>{type}</option>
            {/each}
          </select>
        </div>

        <div class="form-control">
          <label class="label text-sm">ID</label>
          {#if modalMode === 'create' && editingMapping.ClientType}
            <select class="select select-sm select-bordered" bind:value={editingMapping.ClientID}>
              <option value="">Select {editingMapping.ClientType}...</option>
              {#each getClientOptions() as option (option.value)}
                <option value={option.value}>{option.label}</option>
              {/each}
            </select>
          {:else if modalMode === 'edit'}
            <input 
              type="text" 
              class="input input-sm input-bordered" 
              value={editingMapping.ClientName || `${editingMapping.ClientType} ${editingMapping.ClientID}`}
              disabled
            />
          {:else}
            <input 
              type="text" 
              class="input input-sm input-bordered" 
              bind:value={editingMapping.ClientID} 
              placeholder="System ID"
            />
          {/if}
        </div>

        {#if editingMapping.ClientType === 'INST'}
          <div class="form-control">
            <label class="label text-sm">Container</label>
            <select class="select select-sm select-bordered" bind:value={editingMapping.ConDefID}>
              <option value="">Select container...</option>
              {#each containers as container (container.ConDefID)}
                <option value={container.ConDefID}>{container.ConName}</option>
              {/each}
            </select>
          </div>
        {/if}

        <div class="form-control">
          <label class="label text-sm">Test Code</label>
          <input type="text" class="input input-sm input-bordered" bind:value={editingMapping.ClientTestCode} placeholder="Test code in client system" />
        </div>

        <div class="form-control">
          <label class="label text-sm">Test Name</label>
          <input type="text" class="input input-sm input-bordered" bind:value={editingMapping.ClientTestName} placeholder="Test name in client system" />
        </div>
      </div>
    </div>
  </div>

  {#snippet footer()}
    <button class="btn btn-ghost" onclick={() => modalOpen = false}>Cancel</button>
    <button class="btn btn-primary" onclick={saveMapping}>Save</button>
  {/snippet}
</Modal>
