<template>
  <div class="variable-browser">
    <!-- Variable Selection Input with Add Button -->
    <div class="flex items-center space-x-2">
      <div class="flex-1">
        <select
          :value="baseVariableName"
          @change="handleVariableSelect"
          :class="[
            'form-select w-full',
            hasError ? 'border-red-500 focus:border-red-500 focus:ring-red-500' : ''
          ]"
          :disabled="disabled"
        >
          <option value="" disabled>{{ placeholder || 'Select variable' }}</option>
          <optgroup 
            v-for="group in groupedVariables" 
            :key="group.type" 
            :label="group.label"
          >
            <option
              v-for="variable in group.variables"
              :key="variable.name"
              :value="variable.name"
              :title="variable.description || `${variable.type} variable`"
            >
              {{ variable.name }} ({{ variable.type }})
              <span v-if="variable.currentValue !== undefined && variable.currentValue !== null">
                = {{ formatPreviewValue(variable.currentValue, variable.type) }}
              </span>
            </option>
          </optgroup>
        </select>
      </div>
      
      <!-- Add Variable Button (if allowed) -->
      <RsButton 
        v-if="allowCreate"
        @click.stop="openCreateVariable" 
        variant="secondary" 
        size="sm"
        :disabled="disabled"
        title="Create new variable"
        class="flex-shrink-0"
      >
        <Icon name="material-symbols:add" class="w-4 h-4" />
      </RsButton>
    </div>

    <!-- Object Property Path Input (for object/array variables) -->
    <div v-if="selectedVariable && isObjectType(selectedVariable.type) && allowObjectPath" class="mt-2">
      <label class="block text-xs font-medium text-gray-600 mb-1">
        Object Property Path (optional)
      </label>
      <div class="flex items-center space-x-2">
        <div class="flex-1 relative">
          <div class="flex items-center border rounded-md focus-within:ring-2 focus-within:ring-purple-500 focus-within:border-purple-500" :class="propertyPathError ? 'border-red-500' : 'border-gray-300'">
            <span class="px-3 py-2 text-sm text-gray-600 bg-gray-50 border-r border-gray-300 rounded-l-md">
              {{ baseVariableName }}.
            </span>
            <input
              v-model="propertyPath"
              type="text"
              placeholder="data.user.name or [0].title"
              class="flex-1 px-3 py-2 text-sm border-0 rounded-r-md focus:outline-none focus:ring-0"
              @input="handlePropertyPathChange"
              @blur="validatePropertyPath"
            />
          </div>
        </div>
        <button
          v-if="propertyPath"
          @click="clearPropertyPath"
          class="p-2 text-gray-400 hover:text-gray-600 transition-colors"
          title="Clear property path"
        >
          <Icon name="material-symbols:close" class="w-4 h-4" />
        </button>
      </div>
      
      <!-- Property Path Examples -->
      <div class="mt-1 text-xs text-gray-500">
        <details class="cursor-pointer">
          <summary class="hover:text-gray-700">Examples</summary>
          <div class="mt-1 space-y-1 pl-2 border-l-2 border-gray-200">
            <div><code class="bg-gray-100 px-1">data.user.name</code> - Access nested object property</div>
            <div><code class="bg-gray-100 px-1">items[0].title</code> - Access first array item property</div>
            <div><code class="bg-gray-100 px-1">results.users[2].email</code> - Complex nested access</div>
            <div><code class="bg-gray-100 px-1">response.data.attributes.value</code> - Deep nesting</div>
          </div>
        </details>
      </div>

      <!-- Property Path Error -->
      <div v-if="propertyPathError" class="mt-1 text-red-600 text-xs flex items-center">
        <Icon name="material-symbols:error" class="w-3 h-3 mr-1" />
        {{ propertyPathError }}
      </div>

      <!-- Final Variable Path Preview -->
      <div v-if="finalVariablePath && finalVariablePath !== baseVariableName" class="mt-2 p-2 bg-blue-50 border border-blue-200 rounded-md">
        <div class="text-xs font-medium text-blue-800 mb-1">Full Variable Path:</div>
        <code class="text-sm text-blue-700 bg-blue-100 px-2 py-1 rounded">{{ finalVariablePath }}</code>
      </div>
    </div>

    <!-- Variable Info Display -->
    <div v-if="selectedVariable" class="mt-2 p-2 bg-gray-50 rounded-md border text-sm">
      <div class="flex items-center justify-between">
        <div class="flex items-center space-x-2">
          <span 
            class="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium"
            :class="getTypeColorClass(selectedVariable.type)"
          >
            {{ selectedVariable.type }}
          </span>
          <span class="font-medium">{{ selectedVariable.name }}</span>
        </div>
        <div v-if="selectedVariable.currentValue !== undefined" class="text-gray-600">
          Current: {{ formatPreviewValue(selectedVariable.currentValue, selectedVariable.type) }}
        </div>
      </div>
      <div v-if="selectedVariable.description" class="mt-1 text-gray-600">
        {{ selectedVariable.description }}
      </div>
    </div>

    <!-- Error Display -->
    <div v-if="hasError" class="mt-1 text-red-600 text-sm flex items-center">
      <Icon name="material-symbols:error" class="w-4 h-4 mr-1" />
      {{ errorMessage }}
    </div>

    <!-- Create Variable Modal (if enabled) -->
    <Teleport to="body">
      <div
        v-if="showCreateVariable"
        class="variable-modal-overlay"
        @click.self="closeCreateVariable"
      >
        <div class="variable-modal-dialog">
          <div class="variable-modal-content">
            <!-- Modal Header -->
            <div class="variable-modal-header">
              <h4 class="text-lg font-semibold text-gray-900">Create New Variable</h4>
              <button
                @click="closeCreateVariable"
                class="text-gray-400 hover:text-gray-600 transition-colors"
                title="Close"
              >
                <Icon name="material-symbols:close" class="w-5 h-5" />
              </button>
            </div>
            
            <!-- Modal Body -->
            <div class="variable-modal-body">
              <div class="space-y-4">
                <div>
                  <label class="block text-sm font-medium text-gray-700 mb-1">Variable Name</label>
                  <input
                    v-model="newVariableName"
                    type="text"
                    placeholder="Enter variable name"
                    class="w-full p-2 border border-gray-300 rounded-md focus:border-purple-500 focus:ring focus:ring-purple-200"
                    @input="validateVariableName"
                  />
                  <div v-if="nameValidationError" class="mt-1 text-red-600 text-sm">
                    {{ nameValidationError }}
                  </div>
                </div>

                <div>
                  <label class="block text-sm font-medium text-gray-700 mb-1">Data Type</label>
                  <select
                    v-model="newVariableType"
                    class="w-full p-2 border border-gray-300 rounded-md shadow-sm focus:border-purple-500 focus:ring focus:ring-purple-200"
                  >
                    <optgroup label="Common Types">
                      <option value="string">String (Text)</option>
                      <option value="int">Integer (Whole Number)</option>
                      <option value="decimal">Decimal (Number with decimals)</option>
                      <option value="boolean">Boolean (True/False)</option>
                    </optgroup>
                    <optgroup label="Date & Time Types">
                      <option value="date">Date</option>
                      <option value="datetime">DateTime</option>
                      <option value="time">Time</option>
                      <option value="timestamp">Timestamp</option>
                    </optgroup>
                    <optgroup label="Complex Types">
                      <option value="object">Object (JSON)</option>
                      <option value="array">Array (List)</option>
                      <option value="map">Map (Key-Value Pairs)</option>
                    </optgroup>
                    <optgroup label="Special Types">
                      <option value="currency">Currency</option>
                      <option value="percentage">Percentage</option>
                      <option value="email">Email</option>
                      <option value="url">URL</option>
                      <option value="phone">Phone Number</option>
                      <option value="file">File</option>
                      <option value="image">Image</option>
                      <option value="binary">Binary Data</option>
                      <option value="uuid">UUID</option>
                    </optgroup>
                  </select>
                </div>

                <div>
                  <label class="block text-sm font-medium text-gray-700 mb-1">Default Value (Optional)</label>
                  <input
                    v-model="newVariableDefaultValue"
                    type="text"
                    placeholder="Enter default value"
                    class="w-full p-2 border border-gray-300 rounded-md focus:border-purple-500 focus:ring focus:ring-purple-200"
                  />
                </div>

                <div>
                  <label class="block text-sm font-medium text-gray-700 mb-1">Description (Optional)</label>
                  <textarea
                    v-model="newVariableDescription"
                    placeholder="Describe what this variable is used for"
                    rows="2"
                    class="w-full p-2 border border-gray-300 rounded-md focus:border-purple-500 focus:ring focus:ring-purple-200"
                  ></textarea>
                </div>
              </div>
            </div>
            
            <!-- Modal Footer -->
            <div class="variable-modal-footer">
              <RsButton @click="closeCreateVariable" variant="secondary">
                Cancel
              </RsButton>
              <RsButton 
                @click="createVariable" 
                variant="primary"
                :disabled="!canCreateVariable"
              >
                Create Variable
              </RsButton>
            </div>
          </div>
        </div>
      </div>
    </Teleport>
  </div>
</template>

<script setup>
import { ref, computed, watch } from 'vue';
import { useProcessBuilderStore } from '~/stores/processBuilder';
import { Icon } from '#components';

const props = defineProps({
  modelValue: {
    type: String,
    default: ''
  },
  availableVariables: {
    type: Array,
    default: () => []
  },
  placeholder: {
    type: String,
    default: 'Select variable'
  },
  disabled: {
    type: Boolean,
    default: false
  },
  allowCreate: {
    type: Boolean,
    default: true
  },
  filterTypes: {
    type: Array,
    default: () => [] // If specified, only show variables of these types
  },
  required: {
    type: Boolean,
    default: false
  },
  allowObjectPath: {
    type: Boolean,
    default: true // Enable object property path input
  }
});

const emit = defineEmits(['update:modelValue', 'variable-created']);

const processStore = useProcessBuilderStore();

// Create variable state
const showCreateVariable = ref(false);
const newVariableName = ref('');
const newVariableType = ref('string');
const newVariableDefaultValue = ref('');
const newVariableDescription = ref('');
const nameValidationError = ref('');

// Object property path state
const propertyPath = ref('');
const propertyPathError = ref('');

// Computed properties
const baseVariableName = computed(() => {
  // Extract base variable name from modelValue (strip property path)
  const value = props.modelValue || '';
  const dotIndex = value.indexOf('.');
  return dotIndex > -1 ? value.substring(0, dotIndex) : value;
});

const selectedVariable = computed(() => {
  return props.availableVariables.find(v => v.name === baseVariableName.value);
});

const finalVariablePath = computed(() => {
  if (!baseVariableName.value) return '';
  if (!propertyPath.value) return baseVariableName.value;
  return `${baseVariableName.value}.${propertyPath.value}`;
});

const hasError = computed(() => {
  if (!props.required && !props.modelValue) return false;
  if (props.modelValue && !selectedVariable.value) return true;
  if (propertyPathError.value) return true;
  return false;
});

const errorMessage = computed(() => {
  if (props.required && !props.modelValue) {
    return 'Variable selection is required';
  }
  if (props.modelValue && !selectedVariable.value) {
    return `Variable "${baseVariableName.value}" not found`;
  }
  if (propertyPathError.value) {
    return propertyPathError.value;
  }
  return '';
});

const groupedVariables = computed(() => {
  // Initialize with common types but allow for dynamic additions
  const types = {
    string: { label: 'Text Variables', variables: [] },
    int: { label: 'Integer Variables', variables: [] },
    decimal: { label: 'Decimal Variables', variables: [] },
    boolean: { label: 'Boolean Variables', variables: [] },
    date: { label: 'Date Variables', variables: [] },
    datetime: { label: 'DateTime Variables', variables: [] },
    object: { label: 'Object Variables', variables: [] }
    // Other types will be added dynamically
  };

  let variables = props.availableVariables;
  
  // Filter by allowed types if specified
  if (props.filterTypes.length > 0) {
    variables = variables.filter(v => props.filterTypes.includes(v.type));
  }

  variables.forEach(variable => {
    const type = variable.type || 'string';
    
    // If type doesn't exist in our types object, add it dynamically
    if (!types[type]) {
      // Create a friendly label from the type name
      const label = type.charAt(0).toUpperCase() + type.slice(1) + ' Variables';
      types[type] = { label, variables: [] };
    }
    
    // Add the variable to its type group
    types[type].variables.push(variable);
  });

  return Object.values(types).filter(group => group.variables.length > 0);
});

const canCreateVariable = computed(() => {
  return newVariableName.value.trim() && 
         newVariableType.value && 
         !nameValidationError.value;
});

// Methods
const handleVariableSelect = (event) => {
  const selectedVar = event.target.value;
  propertyPath.value = ''; // Reset property path when changing variable
  propertyPathError.value = '';
  emit('update:modelValue', selectedVar);
};

const handlePropertyPathChange = () => {
  propertyPathError.value = ''; // Clear error on input
  emit('update:modelValue', finalVariablePath.value);
};

const validatePropertyPath = () => {
  if (!propertyPath.value) {
    propertyPathError.value = '';
    return;
  }

  // Basic validation for property path syntax
  const path = propertyPath.value.trim();
  
  // Check for invalid characters or patterns
  if (path.includes('..') || path.startsWith('.') || path.endsWith('.')) {
    propertyPathError.value = 'Invalid property path format';
    return;
  }

  // Check for balanced brackets
  const openBrackets = (path.match(/\[/g) || []).length;
  const closeBrackets = (path.match(/\]/g) || []).length;
  if (openBrackets !== closeBrackets) {
    propertyPathError.value = 'Unmatched brackets in property path';
    return;
  }

  propertyPathError.value = '';
};

const clearPropertyPath = () => {
  propertyPath.value = '';
  propertyPathError.value = '';
  emit('update:modelValue', baseVariableName.value);
};

const isObjectType = (type) => {
  return ['object', 'array', 'map', 'set'].includes(type);
};

// Watch for external changes to modelValue to sync property path
watch(() => props.modelValue, (newValue) => {
  if (!newValue) {
    propertyPath.value = '';
    propertyPathError.value = '';
    return;
  }

  const dotIndex = newValue.indexOf('.');
  if (dotIndex > -1) {
    // modelValue contains a property path
    const baseName = newValue.substring(0, dotIndex);
    const path = newValue.substring(dotIndex + 1);
    propertyPath.value = path;
  } else {
    // No property path in modelValue
    propertyPath.value = '';
  }
  propertyPathError.value = '';
}, { immediate: true });

const openCreateVariable = () => {
  showCreateVariable.value = true;
  resetCreateForm();
};

const closeCreateVariable = () => {
  showCreateVariable.value = false;
  resetCreateForm();
};

const resetCreateForm = () => {
  newVariableName.value = '';
  newVariableType.value = 'string';
  newVariableDefaultValue.value = '';
  newVariableDescription.value = '';
  nameValidationError.value = '';
};

const validateVariableName = () => {
  const name = newVariableName.value.trim();
  
  if (!name) {
    nameValidationError.value = '';
    return;
  }

  // Check if name already exists
  if (props.availableVariables.some(v => v.name === name)) {
    nameValidationError.value = 'Variable name already exists';
    return;
  }

  // Check if name is valid (alphanumeric and underscore only)
  if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {
    nameValidationError.value = 'Variable name must start with letter or underscore and contain only letters, numbers, and underscores';
    return;
  }

  nameValidationError.value = '';
};

const createVariable = () => {
  if (!canCreateVariable.value) return;

  const newVariable = {
    name: newVariableName.value.trim(),
    type: newVariableType.value,
    defaultValue: newVariableDefaultValue.value || null,
    description: newVariableDescription.value.trim() || null
  };

  // Add to process store
  processStore.addProcessVariable(newVariable);

  // Select the new variable
  emit('update:modelValue', newVariable.name);
  emit('variable-created', newVariable);

  closeCreateVariable();
};

const getTypeColorClass = (type) => {
  const classes = {
    string: 'bg-blue-100 text-blue-800',
    int: 'bg-purple-100 text-purple-800',
    decimal: 'bg-purple-100 text-purple-800',
    number: 'bg-purple-100 text-purple-800',
    boolean: 'bg-indigo-100 text-indigo-800',
    date: 'bg-amber-100 text-amber-800',
    datetime: 'bg-amber-100 text-amber-800',
    object: 'bg-emerald-100 text-emerald-800',
    // Add colors for any additional types you know about
    array: 'bg-emerald-100 text-emerald-800',
    map: 'bg-teal-100 text-teal-800',
    set: 'bg-teal-100 text-teal-800',
    binary: 'bg-slate-100 text-slate-800',
    time: 'bg-amber-100 text-amber-800',
    timestamp: 'bg-amber-100 text-amber-800',
    uuid: 'bg-violet-100 text-violet-800',
    email: 'bg-blue-100 text-blue-800',
    url: 'bg-blue-100 text-blue-800',
    phone: 'bg-blue-100 text-blue-800',
    currency: 'bg-green-100 text-green-800',
    percentage: 'bg-purple-100 text-purple-800',
    file: 'bg-orange-100 text-orange-800',
    image: 'bg-orange-100 text-orange-800'
  };
  return classes[type] || 'bg-gray-100 text-gray-800';
};

const formatPreviewValue = (value, type) => {
  if (value === null || value === undefined) return 'null';
  
  switch (type) {
    case 'string':
      return value.length > 20 ? `"${value.substring(0, 20)}..."` : `"${value}"`;
    case 'boolean':
      return value ? 'true' : 'false';
    case 'object':
    case 'array':
    case 'map':
    case 'set':
      try {
        const str = typeof value === 'string' ? value : JSON.stringify(value);
        return str.length > 30 ? `${str.substring(0, 30)}...` : str;
      } catch {
        return 'Invalid JSON';
      }
    case 'date':
    case 'datetime':
    case 'time':
    case 'timestamp':
      // Try to format dates nicely if possible
      try {
        if (value instanceof Date) {
          return value.toLocaleString();
        } else if (typeof value === 'string' && (value.includes('T') || value.includes('-'))) {
          return new Date(value).toLocaleString();
        }
      } catch {}
      return String(value);
    case 'int':
    case 'decimal':
    case 'percentage':
    case 'currency':
      // For numeric types
      if (typeof value === 'number') {
        return value.toString();
      }
      return String(value);
    case 'file':
    case 'image':
    case 'binary':
      // For file-like types
      if (typeof value === 'string') {
        return value.length > 20 ? `${value.substring(0, 20)}...` : value;
      }
      return '[Binary Data]';
    default:
      // For any other type, just convert to string
      return String(value);
  }
};
</script>

<style scoped>
.variable-browser .form-select {
  @apply block w-full p-2 border border-gray-300 rounded-md shadow-sm focus:border-purple-500 focus:ring focus:ring-purple-200 text-sm;
}

.variable-browser .form-select:disabled {
  @apply bg-gray-100 text-gray-500 cursor-not-allowed;
}

/* Custom Variable Modal Styles */
.variable-modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 1100;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 1.5rem;
  box-sizing: border-box;
  overflow-y: auto;
  padding-top: 2rem;
}

.variable-modal-dialog {
  position: relative;
  background-color: white;
  border-radius: 0.5rem;
  box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
  margin: 1.5rem auto;
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 3rem);
  width: 100%;
  max-width: 500px;
  animation: modalSlideIn 0.2s ease-out;
}

@keyframes modalSlideIn {
  from {
    opacity: 0;
    transform: translateY(-20px) scale(0.95);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.variable-modal-content {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
}

.variable-modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.25rem 1.5rem;
  border-bottom: 1px solid #e5e7eb;
  background-color: #f9fafb;
  border-radius: 0.5rem 0.5rem 0 0;
}

.variable-modal-body {
  padding: 1.5rem;
  flex: 1;
  overflow-y: auto;
}

.variable-modal-footer {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0.75rem;
  padding: 1rem 1.5rem;
  border-top: 1px solid #e5e7eb;
  background-color: #f9fafb;
  border-radius: 0 0 0.5rem 0.5rem;
}
</style>

<style>
/* Prevent body scroll when modal is open */
body:has(.variable-modal-overlay) {
  overflow: hidden;
}
</style> 