<template>
  <div class="min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 p-6">
    <div class="max-w-6xl mx-auto">
      <h1 class="text-4xl font-bold text-center mb-8 text-gray-900 tracking-tight">Spritesheet generator</h1>
      <div class="flex justify-center space-x-4 mb-8">
        <a href="https://gitea.directonline.io/noxious/spritesheet-generator" target="_blank" class="text-blue-500 hover:text-blue-600 transition-colors"> <i class="fab fa-github"></i> Source </a>
        <a href="https://discord.gg/JTev3nzeDa" target="_blank" class="text-blue-500 hover:text-blue-600 transition-colors"> <i class="fab fa-discord"></i> Discord </a>
        <a href="#" @click.prevent="openHelpModal" class="text-blue-500 hover:text-blue-600 transition-colors"> <i class="fas fa-question-circle"></i> Help </a>
      </div>

      <div class="bg-white rounded-2xl shadow-soft p-8">
        <div class="flex justify-between items-center mb-6">
          <h2 class="text-xl font-semibold text-gray-800">Upload sprites</h2>
          <button @click="openJSONImportDialog" class="px-4 py-2 bg-indigo-500 hover:bg-indigo-600 text-white font-medium rounded-lg transition-colors flex items-center space-x-2">
            <i class="fas fa-file-import"></i>
            <span>Import JSON</span>
          </button>
        </div>
        <file-uploader @upload-sprites="handleSpritesUpload" />
        <input ref="jsonFileInput" type="file" accept=".json,application/json" class="hidden" @change="handleJSONFileChange" />

        <div v-if="sprites.length > 0" class="mt-8">
          <div class="flex flex-wrap items-center gap-6 mb-8">
            <div class="flex items-center space-x-3">
              <label for="columns" class="text-gray-700 font-medium">Columns:</label>
              <input id="columns" type="number" v-model="columns" min="1" max="10" class="w-20 px-3 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all" />
            </div>

            <button @click="downloadSpritesheet" class="px-6 py-2.5 bg-blue-500 hover:bg-blue-600 text-white font-medium rounded-lg transition-colors flex items-center space-x-2">
              <i class="fas fa-download"></i>
              <span>Download spritesheet</span>
            </button>

            <button @click="exportSpritesheetJSON" class="px-6 py-2.5 bg-purple-500 hover:bg-purple-600 text-white font-medium rounded-lg transition-colors flex items-center space-x-2">
              <i class="fas fa-file-code"></i>
              <span>Export as JSON</span>
            </button>

            <button @click="openPreviewModal" class="px-6 py-2.5 bg-green-500 hover:bg-green-600 text-white font-medium rounded-lg transition-colors flex items-center space-x-2">
              <i class="fas fa-play"></i>
              <span>Preview animation</span>
            </button>
          </div>

          <sprite-canvas :sprites="sprites" :columns="columns" @update-sprite="updateSpritePosition" />
        </div>
      </div>
    </div>

    <Modal :is-open="isPreviewModalOpen" @close="closePreviewModal" title="Animation preview">
      <sprite-preview :sprites="sprites" :columns="columns" @update-sprite="updateSpritePosition" />
    </Modal>

    <HelpModal :is-open="isHelpModalOpen" @close="closeHelpModal" />
  </div>
</template>

<script setup lang="ts">
  import { ref } from 'vue';
  import FileUploader from './components/FileUploader.vue';
  import SpriteCanvas from './components/SpriteCanvas.vue';
  import Modal from './components/utilities/Modal.vue';
  import SpritePreview from './components/SpritePreview.vue';
  import HelpModal from './components/HelpModal.vue';

  interface Sprite {
    id: string;
    file: File;
    img: HTMLImageElement;
    url: string;
    width: number;
    height: number;
    x: number;
    y: number;
  }

  const sprites = ref<Sprite[]>([]);
  const columns = ref(4);
  const isPreviewModalOpen = ref(false);
  const isHelpModalOpen = ref(false);
  const jsonFileInput = ref<HTMLInputElement | null>(null);

  const handleSpritesUpload = (files: File[]) => {
    // Check if any of the files is a JSON file
    const jsonFile = files.find(file => file.type === 'application/json' || file.name.endsWith('.json'));

    if (jsonFile) {
      // If it's a JSON file, try to import it
      importSpritesheetJSON(jsonFile);
      return;
    }

    // Otherwise, process as normal image files
    Promise.all(
      files.map(file => {
        return new Promise<Sprite>(resolve => {
          const url = URL.createObjectURL(file);
          const img = new Image();
          img.onload = () => {
            resolve({
              id: crypto.randomUUID(),
              file,
              img,
              url,
              width: img.width,
              height: img.height,
              x: 0,
              y: 0,
            });
          };
          img.src = url;
        });
      })
    ).then(newSprites => {
      sprites.value = [...sprites.value, ...newSprites];
    });
  };

  const updateSpritePosition = (id: string, x: number, y: number) => {
    const spriteIndex = sprites.value.findIndex(sprite => sprite.id === id);
    if (spriteIndex !== -1) {
      sprites.value[spriteIndex].x = x;
      sprites.value[spriteIndex].y = y;
    }
  };

  const downloadSpritesheet = () => {
    if (sprites.value.length === 0) return;

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    // Find max dimensions
    let maxWidth = 0;
    let maxHeight = 0;

    sprites.value.forEach(sprite => {
      if (sprite.width > maxWidth) maxWidth = sprite.width;
      if (sprite.height > maxHeight) maxHeight = sprite.height;
    });

    // Set canvas size
    const rows = Math.ceil(sprites.value.length / columns.value);
    canvas.width = maxWidth * columns.value;
    canvas.height = maxHeight * rows;

    // Apply pixel art optimization for the export canvas
    ctx.imageSmoothingEnabled = false;

    // Draw sprites
    sprites.value.forEach((sprite, index) => {
      const col = index % columns.value;
      const row = Math.floor(index / columns.value);

      const cellX = col * maxWidth;
      const cellY = row * maxHeight;

      ctx.drawImage(sprite.img, cellX + sprite.x, cellY + sprite.y);
    });

    // Create download link
    const link = document.createElement('a');
    link.download = 'spritesheet.png';
    link.href = canvas.toDataURL('image/png');
    link.click();
  };

  // Preview modal control
  const openPreviewModal = () => {
    console.log('Opening preview modal');
    if (sprites.value.length === 0) {
      console.log('No sprites to preview');
      return;
    }
    isPreviewModalOpen.value = true;
  };

  const closePreviewModal = () => {
    isPreviewModalOpen.value = false;
  };

  // Help modal control
  const openHelpModal = () => {
    isHelpModalOpen.value = true;
  };

  const closeHelpModal = () => {
    isHelpModalOpen.value = false;
  };

  // Export spritesheet as JSON with base64 images
  const exportSpritesheetJSON = async () => {
    if (sprites.value.length === 0) return;

    // Create an array to store sprite data with base64 images
    const spritesData = await Promise.all(
      sprites.value.map(async (sprite, index) => {
        // Create a canvas for each sprite to get its base64 data
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');
        if (!ctx) return null;

        // Set canvas size to match the sprite
        canvas.width = sprite.width;
        canvas.height = sprite.height;

        // Draw the sprite
        ctx.drawImage(sprite.img, 0, 0);

        // Get base64 data
        const base64Data = canvas.toDataURL('image/png');

        return {
          id: sprite.id,
          width: sprite.width,
          height: sprite.height,
          x: sprite.x,
          y: sprite.y,
          base64: base64Data,
          name: sprite.file.name,
        };
      })
    );

    // Create JSON object with all necessary data
    const jsonData = {
      columns: columns.value,
      sprites: spritesData.filter(Boolean), // Remove any null values
    };

    // Convert to JSON string
    const jsonString = JSON.stringify(jsonData, null, 2);

    // Create download link
    const blob = new Blob([jsonString], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.download = 'spritesheet.json';
    link.href = url;
    link.click();

    // Clean up
    URL.revokeObjectURL(url);
  };

  // Open file dialog for JSON import
  const openJSONImportDialog = () => {
    jsonFileInput.value?.click();
  };

  // Handle JSON file selection
  const handleJSONFileChange = (event: Event) => {
    const input = event.target as HTMLInputElement;
    if (input.files && input.files.length > 0) {
      const jsonFile = input.files[0];
      importSpritesheetJSON(jsonFile);
      // Reset input value so uploading the same file again will trigger the event
      if (jsonFileInput.value) jsonFileInput.value.value = '';
    }
  };

  // Import spritesheet from JSON
  const importSpritesheetJSON = async (jsonFile: File) => {
    try {
      const jsonText = await jsonFile.text();
      const jsonData = JSON.parse(jsonText);

      if (!jsonData.sprites || !Array.isArray(jsonData.sprites)) {
        throw new Error('Invalid JSON format: missing sprites array');
      }

      // Set columns if available
      if (jsonData.columns && typeof jsonData.columns === 'number') {
        columns.value = jsonData.columns;
      }

      // Process each sprite
      const newSprites = await Promise.all(
        jsonData.sprites.map(async (spriteData: any) => {
          return new Promise<Sprite>(resolve => {
            // Create image from base64
            const img = new Image();
            img.onload = () => {
              // Create a file from the base64 data
              const byteString = atob(spriteData.base64.split(',')[1]);
              const mimeType = spriteData.base64.split(',')[0].split(':')[1].split(';')[0];
              const ab = new ArrayBuffer(byteString.length);
              const ia = new Uint8Array(ab);

              for (let i = 0; i < byteString.length; i++) {
                ia[i] = byteString.charCodeAt(i);
              }

              const blob = new Blob([ab], { type: mimeType });
              const fileName = spriteData.name || `sprite-${spriteData.id}.png`;
              const file = new File([blob], fileName, { type: mimeType });

              resolve({
                id: spriteData.id || crypto.randomUUID(),
                file,
                img,
                url: spriteData.base64,
                width: spriteData.width,
                height: spriteData.height,
                x: spriteData.x || 0,
                y: spriteData.y || 0,
              });
            };
            img.src = spriteData.base64;
          });
        })
      );

      // Replace current sprites with imported ones
      sprites.value = newSprites;
    } catch (error) {
      console.error('Error importing JSON:', error);
      alert('Failed to import JSON file. Please check the file format.');
    }
  };
</script>
