import motors from './motors.json';
import powerSupplies from './powerSupplies.json';
import optionsData from './options.json';
import colors from './colors.json';
import hardwareData from './hardware.json';
import actuatorComponents from './components/actuator.json';
import standComponents from './components/stand.json';
import mountingComponents from './components/mounting.json';
import toyMountsComponents from './components/toyMounts.json';
import remoteComponents from './components/remote.json';
import pcbComponents from './components/pcb.json';

// Create a hardware lookup map from hardware.json
const hardwareLookup = new Map();
Object.values(hardwareData).forEach((category) => {
  Object.values(category).forEach((hardware) => {
    hardwareLookup.set(hardware.id, hardware);
  });
});

// Function to resolve hardware references (IDs) to full hardware definitions
const resolveHardwareReferences = (components) => {
  const resolvedComponents = {};
  
  Object.entries(components).forEach(([componentKey, component]) => {
    resolvedComponents[componentKey] = { ...component };
    
    // Resolve hardwareParts if they exist
    if (component.hardwareParts) {
      resolvedComponents[componentKey].hardwareParts = component.hardwareParts.map((hw) => {
        // If it's already a full object, return as-is
        if (hw.id && hw.name) {
          return hw;
        }
        // If it's a reference (just an ID string or object with hardwareId), resolve it
        const hardwareId = typeof hw === 'string' ? hw : hw.hardwareId || hw.id;
        const hardwareDef = hardwareLookup.get(hardwareId);
        if (!hardwareDef) {
          console.warn(`Hardware not found: ${hardwareId}`);
          return hw;
        }
        // Merge the base definition with any overrides (quantity, relatedParts, required, etc.)
        return {
          ...hardwareDef,
          ...(typeof hw === 'object' ? hw : {}),
          id: hardwareDef.id,
          name: hardwareDef.name,
          description: hardwareDef.description,
          price: hardwareDef.price,
          // required comes from the component reference, not from hardware.json
        };
      });
    }
    
    // Also resolve hardwareParts in systems
    if (component.systems) {
      resolvedComponents[componentKey].systems = {};
      Object.entries(component.systems).forEach(([systemKey, system]) => {
        resolvedComponents[componentKey].systems[systemKey] = { ...system };
        if (system.hardwareParts) {
          resolvedComponents[componentKey].systems[systemKey].hardwareParts = system.hardwareParts.map((hw) => {
            if (hw.id && hw.name) {
              return hw;
            }
            const hardwareId = typeof hw === 'string' ? hw : hw.hardwareId || hw.id;
            const hardwareDef = hardwareLookup.get(hardwareId);
            if (!hardwareDef) {
              console.warn(`Hardware not found: ${hardwareId}`);
              return hw;
            }
            return {
              ...hardwareDef,
              ...(typeof hw === 'object' ? hw : {}),
              id: hardwareDef.id,
              name: hardwareDef.name,
              description: hardwareDef.description,
              price: hardwareDef.price,
              // required comes from the component reference, not from hardware.json
            };
          });
        }
      });
    }
  });
  
  return resolvedComponents;
};

// Combine all component files into a single components object
const rawComponents = {
  ...actuatorComponents,
  ...standComponents,
  ...mountingComponents,
  ...toyMountsComponents,
  ...remoteComponents,
  ...pcbComponents,
};

// Resolve hardware references
const components = resolveHardwareReferences(rawComponents);

// Convert component parts to options format
const convertComponentPartsToOptions = (componentIds, componentData) => {
  if (!componentIds || !Array.isArray(componentIds) || componentIds.length === 0) {
    return componentIds && Array.isArray(componentIds) ? [] : undefined;
  }

  // Check if componentData has systems (new structure) or printedParts (old structure)
  if (componentData?.systems) {
    // Special handling for remotes: flatten knobs from all systems
    if (componentData.category === 'Remote' && componentIds.length > 0) {
      // This is for remote knobs - flatten all knobs from all systems
      const allKnobs = [];
      Object.values(componentData.systems).forEach((system) => {
        if (system.knobs) {
          system.knobs.forEach((knob) => {
            if (componentIds.includes(knob.id)) {
              allKnobs.push({
                id: knob.id,
                name: knob.name,
                description: knob.description,
                image: knob.image || `/images/options/${knob.id}.jpg`,
                filamentEstimate: knob.filamentEstimate !== undefined ? `~${knob.filamentEstimate}g` : "0g",
                hardwareCost: system.hardwareCost !== undefined ? system.hardwareCost : 0,
                price: system.price !== undefined ? system.price : 0,
                timeEstimate: knob.timeEstimate,
                colour: knob.colour,
                type: componentData.type || 'base',
              });
            }
          });
        }
      });
      return allKnobs;
    }
    
    // New structure: systems with printedParts and hardwareParts (for hinges, etc.)
    return componentIds
      .map((systemId) => {
        const system = componentData.systems[systemId];
        if (!system) {
          console.warn(`Component system not found: ${systemId}`);
          return null;
        }
        
        // Calculate total filament estimate from printed parts
        const totalFilament = (system.printedParts || system.bodyParts)?.reduce((sum, part) => {
          return sum + (part.filamentEstimate || 0);
        }, 0) || 0;
        
        return {
          id: systemId,
          name: system.name,
          description: system.description,
          image: system.image || `/images/options/${systemId}.jpg`,
          filamentEstimate: totalFilament > 0 ? `~${totalFilament}g` : "0g",
          hardwareCost: system.hardwareCost !== undefined ? system.hardwareCost : 0,
          price: system.price !== undefined ? system.price : 0,
          colour: (system.printedParts || system.bodyParts)?.[0]?.colour || 'primary',
          type: componentData.type || 'base',
        };
      })
      .filter((opt) => opt !== null);
  }

  // Old structure: printedParts array
  if (!componentData || !componentData.printedParts) {
    console.warn(`Component data not found or missing printedParts/systems`);
    return [];
  }

  return componentIds
    .map((componentId) => {
      const part = componentData.printedParts.find((p) => p.id === componentId);
      if (!part) {
        console.warn(`Component part not found: ${componentId}`);
        return null;
      }
      
      return {
        id: part.id,
        name: part.name,
        description: part.description,
        image: part.image || `/images/options/${part.id}.jpg`,
        filamentEstimate: part.filamentEstimate !== undefined ? `~${part.filamentEstimate}g` : "0g",
        hardwareCost: part.hardwareCost !== undefined ? part.hardwareCost : 0,
        price: part.price !== undefined ? part.price : 0,
        timeEstimate: part.timeEstimate,
        colour: part.colour,
        type: componentData.type || 'base',
      };
    })
    .filter((opt) => opt !== null);
};

// Merge component options into options
const processOptions = (options, componentsData) => {
  const processedOptions = { ...options };
  
  // Process each option category
  Object.keys(processedOptions).forEach((optionKey) => {
    const optionCategory = processedOptions[optionKey];
    if (!optionCategory || !optionCategory.sections) return;
    
    const sections = { ...optionCategory.sections };
    const categoryUseComponents = optionCategory.useComponents;
    
    // Convert component parts to options format for each section
    Object.keys(sections).forEach((sectionKey) => {
      const section = sections[sectionKey];
      
      // Check if section has componentIds to process
      if (section.componentIds !== undefined) {
        // Determine which component category to use
        const componentKey = section.useComponents || categoryUseComponents;
        
        if (componentKey) {
          const componentData = componentsData[componentKey];
          const options = convertComponentPartsToOptions(section.componentIds, componentData);
          // Store component type info for filtering
          section.componentType = componentData?.type || 'base';
          section.options = options;
        } else {
          console.warn(`No useComponents specified for ${optionKey}.${sectionKey}`);
          section.options = [];
        }
        
        // Clean up temporary properties
        delete section.componentIds;
        delete section.useComponents;
      }
    });
    
    processedOptions[optionKey].sections = sections;
    if (categoryUseComponents) {
      delete processedOptions[optionKey].useComponents;
    }
  });
  
  return processedOptions;
};

const options = processOptions(optionsData, components);

export default {
  motors,
  powerSupplies,
  options,
  colors,
  components,
  hardware: hardwareData,
};
