import React, { useState, useEffect, useCallback, useRef } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { Item, WikidataSuggestion, PropertyLabel } from '@/types/database';
import { EditableCell } from './EditableCell';
import { TypeaheadInput } from './TypeaheadInput';
import { v4 as uuidv4 } from 'uuid';

interface ItemsListProps {
  url: string;
}

interface ItemsResponse {
  items: Item[];
  selectedProperties: string[];
}

// API functions
async function loadItemsFromDb(url: string): Promise<ItemsResponse> {
  console.log('[DEBUG] Loading items for URL:', url);
  
  const encodedUrl = encodeURIComponent(url);
  const apiUrl = `/api/urls/${encodedUrl}/items`;
  
  console.log('[DEBUG] Making request to API endpoint:', apiUrl);
  
  const response = await fetch(apiUrl);
  
  if (!response.ok) {
    const errorText = await response.text();
    console.error('[ERROR] Server error:', response.status, errorText);
    throw new Error(`Server error (${response.status}): ${errorText}`);
  }
  
  const items = await response.json();
  console.log('[DEBUG] Successfully parsed', items.length, 'items');
  
  // Get selected properties
  const propertiesResponse = await fetch(`/api/urls/${encodedUrl}/properties`);
  if (!propertiesResponse.ok) {
    throw new Error(`Failed to fetch properties: ${propertiesResponse.status}`);
  }
  
  const selectedProperties = await propertiesResponse.json();
  console.log('[DEBUG] Successfully received selected properties');
  
  // Filter items to only include selected properties
  const filteredItems = items.map((item: Item) => ({
    ...item,
    customProperties: Object.fromEntries(
      Object.entries(item.customProperties).filter(([key]) => 
        selectedProperties.includes(key)
      )
    )
  }));
  
  return { items: filteredItems, selectedProperties };
}

async function saveItemToDb(url: string, item: Item): Promise<void> {
  console.log('[FRONTEND] Saving item - ID:', item.id, 'Name:', item.name);
  
  const encodedUrl = encodeURIComponent(url);
  const response = await fetch(`/api/urls/${encodedUrl}/items`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(item)
  });
  
  if (!response.ok) {
    throw new Error(`Failed to save item: ${response.status}`);
  }
}

async function deleteItemFromDb(url: string, itemId: string): Promise<void> {
  const encodedUrl = encodeURIComponent(url);
  const response = await fetch(`/api/urls/${encodedUrl}/items/${itemId}`, {
    method: 'DELETE'
  });
  
  if (!response.ok) {
    throw new Error(`Failed to delete item: ${response.status}`);
  }
}

async function deletePropertyFromDb(url: string, property: string): Promise<void> {
  const encodedUrl = encodeURIComponent(url);
  const response = await fetch(`/api/urls/${encodedUrl}/properties/${property}`, {
    method: 'DELETE'
  });
  
  if (!response.ok) {
    throw new Error(`Failed to delete property: ${response.status}`);
  }
}

async function addPropertyToDb(url: string, property: string): Promise<void> {
  const encodedUrl = encodeURIComponent(url);
  const response = await fetch(`/api/urls/${encodedUrl}/properties`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(property)
  });
  
  if (!response.ok) {
    throw new Error(`Failed to add property: ${response.status}`);
  }
}

// Wikidata API functions
async function fetchWikidataProperties(wikidataId: string): Promise<Record<string, string>> {
  const sparqlQuery = `
    SELECT ?prop ?propLabel ?value ?valueLabel WHERE {
      wd:${wikidataId} ?prop ?statement.
      ?statement ?ps ?value.
      ?property wikibase:claim ?prop.
      ?property wikibase:statementProperty ?ps.
      SERVICE wikibase:label { 
        bd:serviceParam wikibase:language "en". 
        ?prop rdfs:label ?propLabel.
        ?value rdfs:label ?valueLabel.
      }
    }
  `;

  const url = `https://query.wikidata.org/sparql?query=${encodeURIComponent(sparqlQuery)}&format=json`;
  
  try {
    const response = await fetch(url, {
      headers: { 'Accept': 'application/json' }
    });
    
    if (!response.ok) return {};
    
    const data = await response.json();
    const result: Record<string, string> = {};
    
    if (data.results?.bindings) {
      for (const binding of data.results.bindings) {
        const propUri = binding.prop?.value;
        const value = binding.valueLabel?.value || binding.value?.value || '';
        
        if (propUri) {
          const propId = propUri.split('/').pop() || '';
          result[propId] = value;
        }
      }
    }
    
    return result;
  } catch (error) {
    console.error('Error fetching Wikidata properties:', error);
    return {};
  }
}

async function fetchPropertyLabels(propertyIds: string[]): Promise<Record<string, string>> {
  const cleanIds = propertyIds.map(id => id.replace('http://www.wikidata.org/prop/', ''));
  const propertyIdsStr = cleanIds.join(' wd:');
  
  const sparqlQuery = `
    SELECT ?prop ?propLabel WHERE {
      VALUES ?prop { wd:${propertyIdsStr} }
      SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
    }
  `;

  const url = `https://query.wikidata.org/sparql?query=${encodeURIComponent(sparqlQuery)}&format=json`;
  
  try {
    const response = await fetch(url, {
      headers: { 'Accept': 'application/json' }
    });
    
    if (!response.ok) return {};
    
    const data = await response.json();
    const result: Record<string, string> = {};
    
    if (data.results?.bindings) {
      for (const binding of data.results.bindings) {
        const propUri = binding.prop?.value;
        const label = binding.propLabel?.value || '';
        
        if (propUri) {
          const propId = propUri.split('/').pop() || '';
          result[propId] = label;
        }
      }
    }
    
    return result;
  } catch (error) {
    console.error('Error fetching property labels:', error);
    return {};
  }
}

async function fetchWikidataSuggestions(query: string): Promise<WikidataSuggestion[]> {
  if (!query.trim()) return [];
  
  const url = `https://www.wikidata.org/w/api.php?action=wbsearchentities&search=${encodeURIComponent(query)}&language=en&limit=5&format=json&origin=*`;
  
  try {
    const response = await fetch(url);
    if (!response.ok) return [];
    
    const data = await response.json();
    return data.search || [];
  } catch (error) {
    console.error('Error fetching Wikidata suggestions:', error);
    return [];
  }
}

export function ItemsList({ url }: ItemsListProps) {
  const queryClient = useQueryClient();
  
  // State management
  const [items, setItems] = useState<Item[]>([]);
  const [selectedProperties, setSelectedProperties] = useState<Record<string, boolean>>({});
  const [customProperties, setCustomProperties] = useState<string[]>([]);
  const [propertyLabels, setPropertyLabels] = useState<Record<string, string>>({});
  const [focusedCell, setFocusedCell] = useState<string | null>(null);
  const [focusedItemId, setFocusedItemId] = useState<string | null>(null);
  const [wikidataSuggestions, setWikidataSuggestions] = useState<Record<string, WikidataSuggestion[]>>({});
  const [propertyCache, setPropertyCache] = useState<Record<string, Record<string, string>>>({});
  
  // Refs
  const newPropertyInputRef = useRef<HTMLInputElement>(null);

  // Load items from database
  const { data: itemsData, isLoading, error } = useQuery({
    queryKey: ['items', url],
    queryFn: () => loadItemsFromDb(url),
    staleTime: 30000, // 30 seconds
  });

  // Initialize state when data loads
  useEffect(() => {
    if (itemsData) {
      const { items: loadedItems, selectedProperties: selectedProps } = itemsData;
      
      if (loadedItems.length === 0) {
        // Initialize with one empty item
        const emptyItem: Item = {
          id: uuidv4(),
          name: '',
          description: '',
          wikidataId: undefined,
          customProperties: {}
        };
        setItems([emptyItem]);
      } else {
        setItems(loadedItems);
      }
      
      // Set selected properties
      const selectedPropsMap: Record<string, boolean> = {};
      selectedProps.forEach(prop => {
        selectedPropsMap[prop] = true;
      });
      setSelectedProperties(selectedPropsMap);
      
      // Extract custom properties
      const customProps = Array.from(new Set(
        loadedItems.flatMap(item => Object.keys(item.customProperties))
      ));
      setCustomProperties(customProps);
      
      // Fetch property labels
      if (customProps.length > 0) {
        fetchPropertyLabels(customProps).then(labels => {
          setPropertyLabels(prev => ({ ...prev, ...labels }));
        });
      }
      
      // Set initial focus
      if (loadedItems.length > 0 && !focusedItemId) {
        setFocusedItemId(loadedItems[0].id);
      }
    }
  }, [itemsData, focusedItemId]);

  // Mutations
  const saveItemMutation = useMutation({
    mutationFn: (item: Item) => saveItemToDb(url, item),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['items', url] });
    }
  });

  const deleteItemMutation = useMutation({
    mutationFn: (itemId: string) => deleteItemFromDb(url, itemId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['items', url] });
    }
  });

  const deletePropertyMutation = useMutation({
    mutationFn: (property: string) => deletePropertyFromDb(url, property),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['items', url] });
    }
  });

  const addPropertyMutation = useMutation({
    mutationFn: (property: string) => addPropertyToDb(url, property),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['items', url] });
    }
  });

  // Event handlers
  const updateItem = useCallback((index: number, field: string, value: string) => {
    setItems(prevItems => {
      const newItems = [...prevItems];
      const item = { ...newItems[index] };
      
      if (field === 'name') {
        item.name = value;
        // Fetch Wikidata suggestions
        if (value.trim()) {
          fetchWikidataSuggestions(value).then(suggestions => {
            setWikidataSuggestions(prev => ({
              ...prev,
              [`name-${index}`]: suggestions
            }));
          });
        }
      } else if (field === 'description') {
        item.description = value;
      } else {
        item.customProperties = { ...item.customProperties, [field]: value };
      }
      
      newItems[index] = item;
      
      // Auto-save
      saveItemMutation.mutate(item);
      
      // Add new row if editing last row and value is not empty
      if (index === newItems.length - 1 && value.trim()) {
        const newItem: Item = {
          id: uuidv4(),
          name: '',
          description: '',
          wikidataId: undefined,
          customProperties: {}
        };
        newItems.push(newItem);
        saveItemMutation.mutate(newItem);
      }
      
      return newItems;
    });
  }, [saveItemMutation]);

  const removeItem = useCallback((index: number) => {
    const itemId = items[index].id;
    deleteItemMutation.mutate(itemId);
    setItems(prev => prev.filter((_, i) => i !== index));
  }, [items, deleteItemMutation]);

  const removeProperty = useCallback((property: string) => {
    deletePropertyMutation.mutate(property);
    setCustomProperties(prev => prev.filter(p => p !== property));
    setSelectedProperties(prev => {
      const newSelected = { ...prev };
      delete newSelected[property];
      return newSelected;
    });
    setItems(prev => prev.map(item => ({
      ...item,
      customProperties: Object.fromEntries(
        Object.entries(item.customProperties).filter(([key]) => key !== property)
      )
    })));
  }, [deletePropertyMutation]);

  const addProperty = useCallback(async (property: string) => {
    const normalizedProperty = property.replace('http://www.wikidata.org/prop/', '');
    
    if (!normalizedProperty || selectedProperties[normalizedProperty]) {
      return;
    }
    
    // Add to selected properties
    setSelectedProperties(prev => ({ ...prev, [normalizedProperty]: true }));
    setCustomProperties(prev => [...prev, normalizedProperty]);
    
    // Fetch label if not exists
    if (!propertyLabels[normalizedProperty]) {
      const labels = await fetchPropertyLabels([normalizedProperty]);
      setPropertyLabels(prev => ({ ...prev, ...labels }));
    }
    
    // Add to all items
    setItems(prev => prev.map(item => ({
      ...item,
      customProperties: {
        ...item.customProperties,
        [normalizedProperty]: item.customProperties[normalizedProperty] || ''
      }
    })));
    
    // Save to database
    addPropertyMutation.mutate(normalizedProperty);
    
    // Fetch Wikidata properties for items with wikidata_id
    items.forEach(async (item) => {
      if (item.wikidataId && !propertyCache[item.wikidataId]) {
        const properties = await fetchWikidataProperties(item.wikidataId);
        setPropertyCache(prev => ({ ...prev, [item.wikidataId!]: properties }));
        
        if (properties[normalizedProperty]) {
          setItems(prevItems => prevItems.map(prevItem => 
            prevItem.wikidataId === item.wikidataId
              ? {
                  ...prevItem,
                  customProperties: {
                    ...prevItem.customProperties,
                    [normalizedProperty]: properties[normalizedProperty]
                  }
                }
              : prevItem
          ));
        }
      }
    });
  }, [selectedProperties, propertyLabels, items, propertyCache, addPropertyMutation]);

  const handleWikidataSelect = useCallback(async (suggestion: WikidataSuggestion, itemId: string) => {
    console.log('Wikidata selection for item:', itemId, suggestion);
    
    setItems(prev => prev.map(item => 
      item.id === itemId
        ? {
            ...item,
            name: suggestion.label || '',
            description: suggestion.description || '',
            wikidataId: suggestion.id
          }
        : item
    ));
    
    // Fetch properties for this Wikidata item
    if (suggestion.id) {
      const properties = await fetchWikidataProperties(suggestion.id);
      setPropertyCache(prev => ({ ...prev, [suggestion.id]: properties }));
      
      // Update item with fetched properties
      setItems(prev => prev.map(item => 
        item.id === itemId
          ? {
              ...item,
              customProperties: {
                ...item.customProperties,
                ...Object.fromEntries(
                  Object.entries(properties).filter(([key]) => selectedProperties[key])
                )
              }
            }
          : item
      ));
    }
  }, [selectedProperties]);

  const handleNewPropertyKeyDown = useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === 'Enter') {
      const input = e.currentTarget;
      const inputValue = input.value.trim();
      
      if (inputValue) {
        // Extract property ID from "Label (P123)" format
        const propertyId = inputValue.includes(' (') && inputValue.endsWith(')')
          ? inputValue.split(' (').pop()?.slice(0, -1) || inputValue
          : inputValue;
        
        addProperty(propertyId);
        input.value = '';
      }
    }
  }, [addProperty]);

  if (isLoading) {
    return <div className="p-4">Loading items...</div>;
  }

  if (error) {
    return <div className="p-4 text-red-600">Error loading items: {error.message}</div>;
  }

  return (
    <div className="p-4">
      <h1 className="text-2xl font-bold mb-4">Items List</h1>
      
      <div className="overflow-x-auto">
        <table className="min-w-full border-collapse border border-gray-300">
          <thead>
            <tr>
              <th className="border border-gray-300 p-2 bg-gray-100">Property</th>
              {items.map((item, index) => (
                <th key={item.id} className="border border-gray-300 p-2 bg-gray-100 relative">
                  {item.name || `Item ${index + 1}`}
                  <button
                    onClick={() => removeItem(index)}
                    className="absolute top-1 right-1 w-5 h-5 bg-red-500 text-white rounded-full text-xs hover:bg-red-600"
                    title="Delete item"
                  >
                    ×
                  </button>
                </th>
              ))}
            </tr>
          </thead>
          <tbody>
            {/* Name row */}
            <tr>
              <td className="border border-gray-300 p-2 font-medium">Name</td>
              {items.map((item, index) => (
                <td key={`name-${item.id}`} className="border border-gray-300 p-2">
                  <TypeaheadInput
                    value={item.name}
                    onInput={(value) => updateItem(index, 'name', value)}
                    onSelect={(suggestion) => handleWikidataSelect(suggestion, item.id)}
                    fetchSuggestions={fetchWikidataSuggestions}
                    onFocus={() => setFocusedItemId(item.id)}
                    placeholder="Enter item name"
                  />
                </td>
              ))}
            </tr>
            
            {/* Description row */}
            <tr>
              <td className="border border-gray-300 p-2 font-medium">Description</td>
              {items.map((item, index) => (
                <td key={`description-${item.id}`} className="border border-gray-300 p-2">
                  <EditableCell
                    value={item.description}
                    onInput={(value) => updateItem(index, 'description', value)}
                    focusedCell={focusedCell}
                    setFocusedCell={setFocusedCell}
                    cellKey={`description-${index}`}
                    inputType="textarea"
                  />
                </td>
              ))}
            </tr>
            
            {/* Custom property rows */}
            {customProperties.map((property) => {
              const propertyLabel = propertyLabels[property] || property;
              return (
                <tr key={property}>
                  <td className="border border-gray-300 p-2 font-medium relative">
                    {propertyLabel}
                    <button
                      onClick={() => removeProperty(property)}
                      className="absolute top-1 right-1 w-5 h-5 bg-red-500 text-white rounded-full text-xs hover:bg-red-600"
                      title="Delete property"
                    >
                      ×
                    </button>
                  </td>
                  {items.map((item, index) => (
                    <td key={`${property}-${item.id}`} className="border border-gray-300 p-2">
                      <EditableCell
                        value={item.customProperties[property] || ''}
                        onInput={(value) => updateItem(index, property, value)}
                        focusedCell={focusedCell}
                        setFocusedCell={setFocusedCell}
                        cellKey={`${property}-${index}`}
                        inputType="textarea"
                      />
                    </td>
                  ))}
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
      
      {/* Add new property input */}
      <div className="mt-4">
        <input
          ref={newPropertyInputRef}
          type="text"
          placeholder="Add New Property"
          onKeyDown={handleNewPropertyKeyDown}
          className="px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
          list="properties"
        />
        <datalist id="properties">
          {Object.entries(propertyLabels).map(([propertyId, label]) => {
            const optionValue = `${label} (${propertyId})`;
            return (
              <option key={propertyId} value={optionValue}>
                {optionValue}
              </option>
            );
          })}
        </datalist>
      </div>
    </div>
  );
}