<script setup lang="ts">
import { useGalleryStore } from "../stores/gallery";
import { convertFileSrc } from "@tauri-apps/api/core";
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from "vue";

const store = useGalleryStore();
const isDragging = ref(false);
const dragStart = ref({ x: 0, y: 0 });
const imgRef = ref<HTMLImageElement | null>(null);
const parentRef = ref<HTMLElement | null>(null); // The black background container

// These dimensions will exactly match the rendered image size
const imageRect = ref({ width: 0, height: 0 });

let resizeObserver: ResizeObserver | null = null;

const calculateLayout = () => {
    if (!imgRef.value || !parentRef.value || !store.selectedImage) return;

    // Wait for image natural dimensions to be available
    const natW = imgRef.value.naturalWidth;
    const natH = imgRef.value.naturalHeight;
    
    if (!natW || !natH) return; // Not loaded yet

    const parentW = parentRef.value.clientWidth;
    const parentH = parentRef.value.clientHeight;

    // Calculate 'contain' fit manually
    const scale = Math.min(
        (parentW - 64) / natW, // 64px = 2rem padding * 2 sides (p-8)
        (parentH - 64) / natH
    );
    
    const finalW = Math.floor(natW * scale);
    const finalH = Math.floor(natH * scale);

    imageRect.value = { width: finalW, height: finalH };
};

onMounted(() => {
    // Observe the parent container (window size changes)
    if (parentRef.value) {
        resizeObserver = new ResizeObserver(() => {
            calculateLayout();
        });
        resizeObserver.observe(parentRef.value);
    }
    window.addEventListener('resize', calculateLayout);
});

onUnmounted(() => {
    if (resizeObserver) resizeObserver.disconnect();
    window.removeEventListener('resize', calculateLayout);
});

// Re-calculate when image changes
watch(() => store.selectedImage, () => {
    // Reset size until loaded to avoid jump
    // imageRect.value = { width: 0, height: 0 }; 
    nextTick(() => calculateLayout());
});

// Use either manual position (if override is true) or ZCA suggestion
const position = computed(() => {
    if (store.selectedImage?.manualPosition) {
        return store.selectedImage.manualPosition;
    }
    // Default to bottom center if no ZCA
    return store.selectedImage?.zcaSuggestion ? { x: store.selectedImage.zcaSuggestion.x, y: store.selectedImage.zcaSuggestion.y } : { x: 0.5, y: 0.97 };
});

const effectiveScale = computed(() => store.selectedImage?.scale ?? store.watermarkSettings.scale);
const effectiveOpacity = computed(() => store.selectedImage?.opacity ?? store.watermarkSettings.opacity);
const effectiveColor = computed(() => store.selectedImage?.color ?? store.watermarkSettings.color);

const canvasRef = ref<HTMLCanvasElement | null>(null);
const isDrawing = ref(false);
const currentPath = ref<{x: number, y: number}[]>([]);

// Redraw when strokes change or layout changes
watch(
    () => store.selectedImage?.maskStrokes, 
    () => {
        nextTick(redrawCanvas);
    },
    { deep: true }
);

watch(imageRect, () => {
    nextTick(redrawCanvas);
});

const redrawCanvas = () => {
    if (!canvasRef.value || !store.selectedImage || imageRect.value.width === 0) return;
    const ctx = canvasRef.value.getContext('2d');
    if (!ctx) return;
    
    const w = imageRect.value.width;
    const h = imageRect.value.height;

    ctx.clearRect(0, 0, w, h);
    
    if (!store.selectedImage.maskStrokes) return;

    ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
    ctx.strokeStyle = 'rgba(255, 0, 0, 0.5)';
    ctx.lineCap = 'round';
    ctx.lineJoin = 'round';

    store.selectedImage.maskStrokes.forEach(stroke => {
        if (stroke.type === 'rect' && stroke.rect) {
            ctx.fillRect(
                stroke.rect.x * w, 
                stroke.rect.y * h, 
                stroke.rect.w * w, 
                stroke.rect.h * h
            );
        } else if (stroke.type === 'path' && stroke.points) {
             const lw = (stroke.width || (store.brushSettings.size / w)) * w;
             ctx.lineWidth = lw; 

             if (stroke.points.length > 0) {
                 ctx.beginPath();
                 ctx.moveTo(stroke.points[0].x * w, stroke.points[0].y * h);
                 for (let i = 1; i < stroke.points.length; i++) {
                     ctx.lineTo(stroke.points[i].x * w, stroke.points[i].y * h);
                 }
                 ctx.stroke();
             }
        }
    });
};

const onMouseDown = (e: MouseEvent) => {
    if (store.editMode === 'remove') {
        startDrawing(e);
        return;
    }
    e.preventDefault();
    isDragging.value = true;
    dragStart.value = { x: e.clientX, y: e.clientY };
};

const onMouseMove = (e: MouseEvent) => {
    if (store.editMode === 'remove') {
        draw(e);
        return;
    }

    if (!isDragging.value || !store.selectedImage || imageRect.value.width === 0) return;
    
    const rect = imageRect.value;

    const deltaX = (e.clientX - dragStart.value.x) / rect.width;
    const deltaY = (e.clientY - dragStart.value.y) / rect.height;

    // Update manual position
    let newX = position.value.x + deltaX;
    let newY = position.value.y + deltaY;
    
    // Clamp logic
    const padding = 0.005; 
    newX = Math.max(padding, Math.min(1 - padding, newX));
    newY = Math.max(padding, Math.min(1 - padding, newY));

    // Set ONLY for this image
    store.setImageManualPosition(store.selectedIndex, newX, newY);

    dragStart.value = { x: e.clientX, y: e.clientY };
};


const onMouseUp = () => {
    isDragging.value = false;
    stopDrawing();
};

const onMouseLeave = () => {
    isDragging.value = false;
    stopDrawing();
};

// --- Drawing Logic ---
const startDrawing = (e: MouseEvent) => {
    if (!canvasRef.value) return;
    isDrawing.value = true;
    currentPath.value = [];
    draw(e);
};

const draw = (e: MouseEvent) => {
    if (!isDrawing.value || !canvasRef.value) return;
    const ctx = canvasRef.value.getContext('2d');
    if (!ctx) return;

    const rect = canvasRef.value.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;

    // Normalize
    const nx = x / imageRect.value.width;
    const ny = y / imageRect.value.height;
    
    currentPath.value.push({ x: nx, y: ny });

    // Live feedback (Paint on top of existing)
    ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
    ctx.beginPath();
    ctx.arc(x, y, store.brushSettings.size / 2, 0, Math.PI * 2);
    ctx.fill();
    
    // Connect dots for smoothness if we have enough points
    // (Optional optimization: draw line from last point)
};

const stopDrawing = () => {
    if (!isDrawing.value) return;
    isDrawing.value = false;
    
    if (currentPath.value.length > 0 && store.selectedIndex >= 0) {
        const normWidth = store.brushSettings.size / imageRect.value.width;
        store.addMaskStroke(store.selectedIndex, {
            type: 'path',
            points: [...currentPath.value],
            width: normWidth
        });
    }
};
</script>

<template>
  <div 
    ref="parentRef"
    class="absolute inset-0 flex items-center justify-center bg-black overflow-hidden"
    @mousemove="onMouseMove"
    @mouseup="onMouseUp"
    @mouseleave="onMouseLeave"
  >
    <!-- 
      Dynamic Wrapper:
      Dimensions strictly equal to the rendered image size.
      This serves as the coordinate system for the watermark.
    -->
    <div 
        v-if="store.selectedImage" 
        class="relative shadow-2xl" 
        :style="{
            width: imageRect.width + 'px',
            height: imageRect.height + 'px'
        }"
    >
      <img 
        ref="imgRef"
        :src="convertFileSrc(store.selectedImage.path)" 
        class="block w-full h-full select-none pointer-events-none"
        alt="Hero Image"
        loading="eager"
        decoding="sync"
        fetchpriority="high"
        @load="calculateLayout"
        @error="(e) => console.error('Hero Image Load Error:', e)"
      />
      
      <!-- Text Watermark Overlay (Only in Add Mode) -->
      <div 
        v-if="store.editMode === 'add' && store.watermarkSettings.text"
        class="absolute cursor-move select-none whitespace-nowrap font-medium"
        :style="{
            left: (position.x * 100) + '%',
            top: (position.y * 100) + '%',
            transform: 'translate(-50%, -50%)',
            opacity: effectiveOpacity,
            color: effectiveColor,
            /* Scale based on HEIGHT of the IMAGE */
            fontSize: (imageRect.height * effectiveScale) + 'px',
            fontFamily: 'Roboto, sans-serif',
            height: '0px', 
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            zIndex: 10
        }"
        @mousedown="onMouseDown"
      >
        <span> 
            {{ store.watermarkSettings.text }}
        </span>
        
        <!-- Selection Ring when dragging -->
        <div v-if="isDragging" class="absolute -inset-2 border border-blue-500 rounded-sm"></div>
      </div>

      <!-- Canvas Overlay (Only in Remove Mode) -->
      <canvas 
        v-show="store.editMode === 'remove'"
        ref="canvasRef"
        :width="imageRect.width"
        :height="imageRect.height"
        class="absolute inset-0 z-20 cursor-crosshair touch-none"
        @mousedown="onMouseDown"
      ></canvas>
    </div>
    <div v-else class="text-gray-500 flex flex-col items-center">
      <p>未选择图片</p>
    </div>
  </div>
</template>

<style scoped>
.image-container {
    /* Removed container-type: size to prevent layout collapse */
}

span {
    text-shadow: 
        -1px -1px 0 #000,  
         1px -1px 0 #000,
        -1px  1px 0 #000,
         1px  1px 0 #000;
}
</style>
