import { getHistory, runPrompt } from "../apis/comfyApiCustom";
import { app } from "../utils/comfyapp";

export type WidgetParamConf = {
    nodeId: number;
    paramName: string;
    paramValue: string;
}

function updatePrompt(prompt_output: any, paramConfigs: WidgetParamConf[]): any {
    try {
        if (!prompt_output) {
            console.error("Invalid prompt_output: ", prompt_output);
            return prompt_output;
        }
        
        // Apply each parameter configuration
        for (const config of paramConfigs) {
            if (!prompt_output[config.nodeId]) {
                console.error(`Node with ID ${config.nodeId} not found`);
                continue;
            }
            
            if (!prompt_output[config.nodeId]["inputs"]) {
                console.error(`Inputs not found for node with ID ${config.nodeId}`);
                continue;
            }
            
            // Update each parameter for this node
            prompt_output[config.nodeId]["inputs"][config.paramName] = config.paramValue;
            
        }
        
        return prompt_output;
    } catch (error) {
        console.error("Error updating prompt:", error);
        return prompt_output;
    }
}

export async function queuePrompt(paramConfigs: WidgetParamConf[]): Promise<any> {
    const prompt = await app.graphToPrompt()
    const updated_prompt = updatePrompt(prompt.output, paramConfigs)
    console.log("queuePrompt updated_prompt:", updated_prompt);
    const request_body = {
        prompt: updated_prompt,
        client_id: app.api.clientId,
        extra_data: {
            extra_pageinfo: {
                workflow: prompt.workflow,
            }
        }
    }
    console.debug("queuePrompt request_body.prompt:", updated_prompt);
    const response = await runPrompt(request_body);
    console.debug("queuePrompt response:", response);
    return response;
}

function createErrorImage(errorMessage: string): string {
  // Create a data URL for an error image with the provided error message
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  
  // Set canvas dimensions
  canvas.width = 512;
  canvas.height = 512;
  
  if (ctx) {
    // Fill background
    ctx.fillStyle = '#f8d7da';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    
    // Draw border
    ctx.strokeStyle = '#dc3545';
    ctx.lineWidth = 4;
    ctx.strokeRect(10, 10, canvas.width - 20, canvas.height - 20);
    
    // Draw error icon
    ctx.fillStyle = '#dc3545';
    ctx.beginPath();
    ctx.arc(canvas.width / 2, 150, 50, 0, 2 * Math.PI);
    ctx.fill();
    
    // Draw exclamation mark
    ctx.fillStyle = 'white';
    ctx.font = 'bold 80px Arial';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText('!', canvas.width / 2, 150);
    
    // Draw error text
    ctx.fillStyle = '#721c24';
    ctx.font = '20px Arial';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    
    // Handle multi-line text
    const maxWidth = canvas.width - 60;
    const lineHeight = 30;
    const words = errorMessage.split(' ');
    let line = '';
    let y = 250;
    
    for (let i = 0; i < words.length; i++) {
      const testLine = line + words[i] + ' ';
      const metrics = ctx.measureText(testLine);
      const testWidth = metrics.width;
      
      if (testWidth > maxWidth && i > 0) {
        ctx.fillText(line, canvas.width / 2, y);
        line = words[i] + ' ';
        y += lineHeight;
      } else {
        line = testLine;
      }
    }
    ctx.fillText(line, canvas.width / 2, y);
  }
  
  return canvas.toDataURL('image/png');
}

export async function getOutputImagesByPromptId(promptId: string): Promise<{[nodeId: string]: string[]}> {
    try {
      if(!promptId || promptId === "") {
        console.log("No prompt ID provided");
        return { "1": [createErrorImage("Fail to generate prompt ID")] };
      }
  
      // Get the history for the prompt
      const history = await getHistory(promptId);
      
      if (!history || !history[promptId]) {
        console.log("Not finished for prompt ID:", promptId);
        return {};
      }

      const promptHistory = history[promptId];
      if(promptHistory.status && promptHistory.status.status_str === "error") {
        console.error("Error for prompt ID:", promptId);
        const messages = promptHistory.status.messages;
        if(messages && messages.length > 0) {
            const lastMessage = messages[messages.length - 1];
            if(lastMessage && lastMessage.length > 0) {
                const errorMessage = lastMessage[0];
                // Return an error image with the error message
                const errorImage = createErrorImage(errorMessage);
                return { "1": [errorImage] }; // Return with default nodeId of 1
            }
        }
      }
      
      const outputImages: {[nodeId: string]: string[]} = {};
      
      // Process all outputs in the history
      if (promptHistory.outputs) {
        for (const nodeId in promptHistory.outputs) {
          const nodeOutput = promptHistory.outputs[nodeId];
          if (nodeOutput && nodeOutput.images) {
            outputImages[nodeId] = [];
            
            // Process each image for this node
            for (const img of nodeOutput.images) {
              if (img && img.filename && img.type) {
                // Construct the image URL using the ComfyUI view endpoint
                // const imageUrl = `${window.location.origin}/view?filename=${encodeURIComponent(img.filename)}&type=${encodeURIComponent(img.type)}${img.subfolder ? '&subfolder=' + encodeURIComponent(img.subfolder) : ''}`;
                //app.graph._nodes_by_id[3].imgs[0].currentSrc
                const urlBase = app?.graph._nodes_by_id?.[nodeId]?.imgs?.[0]?.currentSrc?.split("?")[0];
                outputImages[nodeId].push(urlBase + "?filename=" + encodeURIComponent(img.filename) + "&type=" + encodeURIComponent(img.type) + (img.subfolder ? "&subfolder=" + encodeURIComponent(img.subfolder) : ""));
              }
            }
            
            console.log("outputImages for nodeId:", nodeId, outputImages[nodeId]);
          }
        }
      }
      
      return outputImages;
    } catch (error) {
      console.error("Error getting output images from prompt:", error);
      throw error;
    }
  }

// Define node interface for type safety
interface ComfyNode {
  id: number;
  type: string;
  [key: string]: any;
}

export function getOnlyOneImageNode() {
  const nodes = Object.values(app.graph._nodes_by_id) as ComfyNode[];
  const saveNodeIds = [];
  const previewNodeIds = [];
  
  for(const node of nodes) {
    if(node.type === "SaveImage") {
      saveNodeIds.push(node.id);
    } else if(node.type === "PreviewImage") {
      previewNodeIds.push(node.id);
    }
  }
  console.log("saveNodeIds:", saveNodeIds);
  console.log("previewNodeIds:", previewNodeIds);
  if(saveNodeIds.length === 0 && previewNodeIds.length === 0) {
    throw new Error("No SaveImage or PreviewImage node found, please add one to the graph");
  }
  if(saveNodeIds.length === 1) {
    return saveNodeIds[0];
  } else if(saveNodeIds.length == 0 && previewNodeIds.length === 1) {
    return previewNodeIds[0];
  } else {
    // Return all node IDs as an array so the UI can handle selection
    return null;
  }
}

export async function getOutputImageByPromptId(promptId: string, nodeId: Number): Promise<string | null> {
    const outputImages = await getOutputImagesByPromptId(promptId);
    // If no images were found, return an empty array
    if (Object.keys(outputImages).length === 0) {
        return null;
    }
    
    // Find the maximum nodeId
    // const nodeIds = Object.keys(outputImages).map(id => parseInt(id));
    // const maxNodeId = Math.max(...nodeIds).toString();
    
    if (outputImages[nodeId.toString()] && outputImages[nodeId.toString()].length > 0) {
      return outputImages[nodeId.toString()][0];
    }
    
    return null;
}