import React, { useState, useEffect, FormEvent, ChangeEvent } from 'react';

interface InputData {
  prompt: string;
  negative_prompt: string;
  image: File | null;
  mask: File | null;
  width: number;
  height: number;
  num_outputs: number;
  scheduler: string;
  num_inference_steps: number;
  guidance_scale: number;
  prompt_strength: number;
  seed: string;
  refine: string;
  high_noise_frac: number;
  refine_steps: string;
  apply_watermark: boolean;
  lora_scale: number;
}

interface Prediction {
  output: string[];
}

interface OutputData {
  prediction: Prediction | null;
  timestamp: string;
  prompt: string;
}

const TruncatedText = ({ text }: { text: string }) => {
  const [isTruncated, setIsTruncated] = useState(true);

  const toggleTruncated = () => {
    setIsTruncated(!isTruncated);
  };

  if (text.length < 34) {
    return <span>{text}</span>;
  }

  return (
    <span>
      {isTruncated ? `${text.substring(0, 24)}...` : text}
      <button onClick={toggleTruncated}>
        {isTruncated ? 'Read More' : 'Read Less'}
      </button>
    </span>
  );
};

const IndexPage = () => {
  const [inputData, setInputData] = useState<InputData>({
    prompt: '',
    negative_prompt: '',
    image: null,
    mask: null,
    width: 1024,
    height: 1024,
    num_outputs: 1,
    scheduler: 'K_EULER',
    num_inference_steps: 50,
    guidance_scale: 7.5,
    prompt_strength: 0.8,
    seed: '',
    refine: 'no_refiner',
    high_noise_frac: 0.8,
    refine_steps: '',
    apply_watermark: false,
    lora_scale: 0.6,
  });

  const [output, setOutput] = useState<OutputData[]>([]);
  const [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    const savedOutput = localStorage.getItem('output');
    if (savedOutput) {
      setOutput(JSON.parse(savedOutput));
    }
  }, []);


  const handleChange = (e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) => {
    const { name, value, type } = e.target as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
    
    // Handle file inputs differently
    if (type === 'file') {
      const files = (e.target as HTMLInputElement).files;
      setInputData((prevData) => ({ ...prevData, [name]: files ? files[0] : null }));
    } else if (type === 'checkbox') {
      // Check if the 'checked' property exists before accessing it
      if ('checked' in e.target) {
        setInputData((prevData) => ({ ...prevData, [name]: (e.target as HTMLInputElement).checked }));
      }
    } else {
      setInputData((prevData) => ({ ...prevData, [name]: value }));
    }
  };
  

  const handleSubmit = async (e: FormEvent) => {
    e.preventDefault();
    setIsLoading(true);
    try {
      const formData = new FormData();
      for (const key in inputData) {
        // Changed this line to fix the 'no-prototype-builtins' error
        if (Object.prototype.hasOwnProperty.call(inputData, key)) {
          const inputKey = key as keyof InputData;
          if (typeof inputData[inputKey] === 'string' || inputData[inputKey] instanceof Blob) {
            formData.append(inputKey, inputData[inputKey] as string | Blob);
          }
        }
      }

      const response = await fetch('/api/replicate_logo', {
        method: 'POST',
        body: formData,
      });

      const result = await response.json();

      if (response.ok) {
        const timestamp = new Date().toISOString();
        const newOutput = {
          prediction: result.prediction,
          timestamp,
          prompt: inputData.prompt,
        };
        const updatedOutput = [...output, newOutput];
        setOutput(updatedOutput);
        localStorage.setItem('output', JSON.stringify(updatedOutput));
        setInputData({
          prompt: '',
          negative_prompt: '',
          image: null,
          mask: null,
          width: 1024,
          height: 1024,
          num_outputs: 1,
          scheduler: 'K_EULER',
          num_inference_steps: 50,
          guidance_scale: 7.5,
          prompt_strength: 0.8,
          seed: '',
          refine: 'no_refiner',
          high_noise_frac: 0.8,
          refine_steps: '',
          apply_watermark: false,
          lora_scale: 0.6,
        });
      }
    } catch (error) {
      console.error("An error occurred:", error);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div className="bg-gray-900 text-white p-4 container mx-auto" style={{ minHeight: '100vh' }}>
      <h1 className="text-2xl mb-4">Image Generation App</h1>
      <form onSubmit={handleSubmit} className="space-y-4">
        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
          {/* Textareas take full width */}
          <div className="col-span-full">
            <textarea
              name="prompt"
              value={inputData.prompt}
              onChange={handleChange}
              className="p-2 bg-gray-800 rounded border border-gray-600 w-full h-24"
              placeholder="Input prompt"
            ></textarea>
          </div>
          <div className="col-span-full">
            <textarea
              name="negative_prompt"
              value={inputData.negative_prompt}
              onChange={handleChange}
              className="p-2 bg-gray-800 rounded border border-gray-600 w-full h-24"
              placeholder="Input Negative Prompt"
            ></textarea>
          </div>
  
          {/* Single row, multiple items */}
          <div>
            <input
              type="file"
              name="image"
              accept="image/*"
              onChange={handleChange}
              className="p-2 bg-gray-800 rounded border border-gray-600 w-full"
            />
          </div>
          <div>
            <input
              type="file"
              name="mask"
              accept="image/*"
              onChange={handleChange}
              className="p-2 bg-gray-800 rounded border border-gray-600 w-full"
            />
          </div>
          <div>
            <input
              type="number"
              name="width"
              value={inputData.width}
              onChange={handleChange}
              className="p-2 bg-gray-800 rounded border border-gray-600 w-full"
              placeholder="Width"
            />
          </div>
          <div>
            <input
              type="number"
              name="height"
              value={inputData.height}
              onChange={handleChange}
              className="p-2 bg-gray-800 rounded border border-gray-600 w-full"
              placeholder="Height"
            />
          </div>
          <div>
            <input
              type="number"
              name="num_outputs"
              value={inputData.num_outputs}
              onChange={handleChange}
              className="p-2 bg-gray-800 rounded border border-gray-600 w-full"
              placeholder="Number of Outputs"
            />
          </div>
          <div>
            <input
              type="number"
              name="num_inference_steps"
              value={inputData.num_inference_steps}
              onChange={handleChange}
              className="p-2 bg-gray-800 rounded border border-gray-600 w-full"
              placeholder="Number of Inference Steps"
            />
          </div>
          <div>
            <input
              type="number"
              name="guidance_scale"
              value={inputData.guidance_scale}
              onChange={handleChange}
              className="p-2 bg-gray-800 rounded border border-gray-600 w-full"
              placeholder="Guidance Scale"
            />
          </div>
          <div>
            <input
              type="number"
              name="prompt_strength"
              value={inputData.prompt_strength}
              onChange={handleChange}
              className="p-2 bg-gray-800 rounded border border-gray-600 w-full"
              placeholder="Prompt Strength"
            />
          </div>
          <div>
            <input
              type="text"
              name="seed"
              value={inputData.seed}
              onChange={handleChange}
              className="p-2 bg-gray-800 rounded border border-gray-600 w-full"
              placeholder="Seed"
            />
          </div>
          <div className="col-span-full">
            <select
              id="refine"
              name="refine"
              value={inputData.refine}
              onChange={handleChange}
              className="w-full p-2 bg-gray-800 rounded border border-gray-600 disabled:cursor-not-allowed disabled:opacity-50 text-white"
            >
              <option value="no_refiner">no_refiner</option>
              <option value="expert_ensemble_refiner">expert_ensemble_refiner</option>
              <option value="base_image_refiner">base_image_refiner</option>
            </select>
          </div>
          <div>
            <input
              type="number"
              name="high_noise_frac"
              value={inputData.high_noise_frac}
              onChange={handleChange}
              className="p-2 bg-gray-800 rounded border border-gray-600 w-full"
              placeholder="High Noise Fraction"
            />
          </div>
          <div className="col-span-full">
            <label className="flex items-center">
              <input
                type="checkbox"
                name="apply_watermark"
                checked={inputData.apply_watermark}
                onChange={handleChange}
                className="mr-2"
              />
              Apply Watermark
            </label>
          </div>
          <div>
            <input
              type="number"
              name="lora_scale"
              value={inputData.lora_scale}
              onChange={handleChange}
              className="p-2 bg-gray-800 rounded border border-gray-600 w-full"
              placeholder="LoRA Scale"
            />
          </div>
        </div>
        
        {/* Submit button */}
        <button
          type="submit"
          className={`p-2 px-5 rounded ${isLoading ? 'bg-gray-600' : 'bg-green-600'} text-white`}
          disabled={isLoading}
          style={{ cursor: isLoading ? 'not-allowed' : 'pointer' }}
        >
          {isLoading ? 'Generating...' : 'Generate'}
        </button>
      </form>
      
      <div className="grid lg:grid-cols-3 grid-cols-1 gap-4 mt-8">
  {output.map((imageData, index) => (
    <div key={index} className="space-y-2">
      <h2 className="text-xl">Generated Image {index + 1}:</h2>
      {imageData.prediction?.output ? (
        <div className="relative">
          <img src={imageData.prediction.output[0]} alt={`Generated Image ${index + 1}`} />
          <button
            onClick={async () => {
              try {
                const response = await fetch(imageData.prediction?.output[0] || ""); // Used optional chaining and default to empty string
                const blob = await response.blob();
                const url = window.URL.createObjectURL(blob);
                const link = document.createElement('a');
                link.href = url;
                link.download = `generated_image_${index + 1}.png`;
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
                window.URL.revokeObjectURL(url);
              } catch (error) {
                console.error("Failed to download the image", error);
              }
            }}
            className="absolute top-0 right-0 bg-green-600 text-white px-3 py-1 rounded"
          >
            Download
          </button>
        </div>
      ) : (
        <p>Image URLs not available.</p>
      )}
      <p>Date: {new Date(imageData.timestamp).toLocaleDateString()} Time: {new Date(imageData.timestamp).toLocaleTimeString()}</p>
      <TruncatedText text={imageData.prompt} />
    </div>
  ))}
</div>


  </div>
)}

export default IndexPage;
