import React, { useState, useRef, useEffect } from 'react';
import * as pdfjs from 'pdfjs-dist';
import { useLanguage } from '../contexts/LanguageContext';

// Set worker path for PDF.js
pdfjs.GlobalWorkerOptions.workerSrc = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.mjs`;

// Helper function to convert coordinates between different scales
const convertCoordinates = (
    x: number,
    y: number,
    containerWidth: number,
    containerHeight: number,
    pdfWidth: number,
    pdfHeight: number,
    zoomLevel: number = 1.0
) => {
    // Calculate the scale factors to fit the PDF page in the container while maintaining aspect ratio
    const scaleX = containerWidth / pdfWidth;
    const scaleY = containerHeight / pdfHeight;
    let scale = Math.min(scaleX, scaleY);

    // Apply zoom level to the scale
    scale *= zoomLevel;

    // Calculate padding offsets to center the PDF page in the container
    const paddedWidth = pdfWidth * scale;
    const paddedHeight = pdfHeight * scale;
    const offsetX = (containerWidth - paddedWidth) / 2;
    const offsetY = (containerHeight - paddedHeight) / 2;

    // Convert from container coordinates to PDF page coordinates
    const pdfX = (x - offsetX) / scale;
    const pdfY = (y - offsetY) / scale;

    return { x: pdfX, y: pdfY, scale, offsetX, offsetY };
};

// Function to calculate how PDF page is laid out in container space
const calculatePDFLayout = (
    containerWidth: number,
    containerHeight: number,
    pdfWidth: number,
    pdfHeight: number,
    zoomLevel: number = 1.0
) => {
    // Calculate the scale factors to fit the PDF page in the container while maintaining aspect ratio
    const scaleX = containerWidth / pdfWidth;
    const scaleY = containerHeight / pdfHeight;
    let pageScale = Math.min(scaleX, scaleY);

    // Apply zoom level to the page scale
    pageScale *= zoomLevel;

    // Calculate padding offsets to center the PDF page in the container
    const paddedWidth = pdfWidth * pageScale;
    const paddedHeight = pdfHeight * pageScale;
    const offsetX = (containerWidth - paddedWidth) / 2;
    const offsetY = (containerHeight - paddedHeight) / 2;

    return {
        pageScale,
        offsetX: Math.round(offsetX),
        offsetY: Math.round(offsetY),
        paddedWidth,
        paddedHeight
    };
};

// Enhanced function to calculate precise PDF page layout with improved accuracy
const calculatePrecisePDFLayout = (
    containerWidth: number,
    containerHeight: number,
    pdfWidth: number,
    pdfHeight: number,
    zoomLevel: number = 1.0
) => {
    // Calculate scale to fit the PDF page in the container while maintaining aspect ratio
    const scaleX = containerWidth / pdfWidth;
    const scaleY = containerHeight / pdfHeight;
    let pageScale = Math.min(scaleX, scaleY);

    // Apply zoom level to the page scale
    pageScale *= zoomLevel;

    // Calculate exact page dimensions after scaling
    const scaledPageWidth = pdfWidth * pageScale;
    const scaledPageHeight = pdfHeight * pageScale;

    // Calculate padding to center the page in the container
    const offsetX = (containerWidth - scaledPageWidth) / 2;
    const offsetY = (containerHeight - scaledPageHeight) / 2;

    return {
        pageScale,
        offsetX: offsetX,
        offsetY: offsetY,
        scaledPageWidth,
        scaledPageHeight,
        containerWidth,
        containerHeight
    };
};

export interface SelectionCoordinates {
    x: number;
    y: number;
    width: number;
    height: number;
}

interface PDFSelectionToolProps {
    containerRef: React.RefObject<HTMLDivElement>;
    canvasRef: React.RefObject<HTMLCanvasElement>;
    onSelectionComplete: (screenshot: Blob, text: string) => void;
    onCancel: () => void;
    pdfBlob: Blob | null;
    pageNumber: number;
    authToken: string;
    zoomLevel?: number;  // オプションのズームレベルパラメータ
}

export const PDFSelectionTool: React.FC<PDFSelectionToolProps> = ({
    containerRef,
    canvasRef,
    onSelectionComplete,
    onCancel,
    pdfBlob,
    pageNumber,
    authToken,
    zoomLevel = 1.0,  // デフォルトのズームレベルは1.0
}) => {
    const { t } = useLanguage();
    const [isSelecting, setIsSelecting] = useState(false);
    const [startPoint, setStartPoint] = useState<{ x: number; y: number } | null>(null);
    const [currentPoint, setCurrentPoint] = useState<{ x: number; y: number } | null>(null);
    const overlayCanvasRef = useRef<HTMLCanvasElement>(null);

    useEffect(() => {
        const handleKeyDown = (e: KeyboardEvent) => {
            if (e.key === 'Escape') {
                onCancel();
            }
        };

        window.addEventListener('keydown', handleKeyDown);
        return () => window.removeEventListener('keydown', handleKeyDown);
    }, [onCancel]);

    const handleMouseDown = (e: React.MouseEvent) => {
        if (!containerRef.current || !pdfBlob) return;

        const rect = containerRef.current.getBoundingClientRect();
        // コンテナに対する実際の座標を使用
        const x = e.clientX - rect.left;
        const y = e.clientY - rect.top;

        setStartPoint({ x, y });
        setCurrentPoint({ x, y });
        setIsSelecting(true);
    };

    const handleMouseMove = (e: React.MouseEvent) => {
        if (!isSelecting || !containerRef.current) return;

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

        setCurrentPoint({ x, y });
    };

    const handleMouseUp = async () => {
        if (!isSelecting || !startPoint || !currentPoint || !containerRef.current || !canvasRef.current) return;

        setIsSelecting(false);

        // Calculate selection rectangle based on mouse events (in container coordinates)
        const startX = Math.min(startPoint.x, currentPoint.x);
        const startY = Math.min(startPoint.y, currentPoint.y);
        const endX = Math.max(startPoint.x, currentPoint.x);
        const endY = Math.max(startPoint.y, currentPoint.y);
        const width = endX - startX;
        const height = endY - startY;

        // Minimum selection size
        if (width < 10 || height < 10) {
            onCancel();
            return;
        }

        try {
            // Get the actual canvas element from PDFPreview
            const sourceCanvas = canvasRef.current;
            const containerRect = containerRef.current.getBoundingClientRect();

            console.log('=== Direct Canvas Capture ===');
            console.log('Container dimensions:', { width: containerRect.width, height: containerRect.height });
            console.log('Canvas dimensions:', { width: sourceCanvas.width, height: sourceCanvas.height });
            console.log('Selection in container space:', { startX, startY, endX, endY, width, height });

            // Get the canvas bounding rect to find where it's positioned within the container
            const canvasRect = sourceCanvas.getBoundingClientRect();
            const canvasOffsetX = canvasRect.left - containerRect.left;
            const canvasOffsetY = canvasRect.top - containerRect.top;

            console.log('Canvas position in container:', { offsetX: canvasOffsetX, offsetY: canvasOffsetY });
            console.log('Canvas display size:', { width: canvasRect.width, height: canvasRect.height });

            // Calculate selection relative to the canvas element
            const selectionRelativeToCanvas = {
                x: startX - canvasOffsetX,
                y: startY - canvasOffsetY,
                width: width,
                height: height
            };

            console.log('Selection relative to canvas:', selectionRelativeToCanvas);

            // Calculate the scale factor between canvas display size and actual pixel size
            // The canvas may be rendered at higher resolution (devicePixelRatio)
            const scaleX = sourceCanvas.width / canvasRect.width;
            const scaleY = sourceCanvas.height / canvasRect.height;

            console.log('Canvas scale factors:', { scaleX, scaleY });

            // Convert selection coordinates to canvas pixel coordinates
            const canvasX = Math.round(selectionRelativeToCanvas.x * scaleX);
            const canvasY = Math.round(selectionRelativeToCanvas.y * scaleY);
            const canvasWidth = Math.round(selectionRelativeToCanvas.width * scaleX);
            const canvasHeight = Math.round(selectionRelativeToCanvas.height * scaleY);

            console.log('Selection in canvas pixel space:', { canvasX, canvasY, canvasWidth, canvasHeight });

            // Ensure coordinates are within canvas bounds
            const safeX = Math.max(0, Math.min(canvasX, sourceCanvas.width));
            const safeY = Math.max(0, Math.min(canvasY, sourceCanvas.height));
            const safeWidth = Math.max(0, Math.min(canvasWidth, sourceCanvas.width - safeX));
            const safeHeight = Math.max(0, Math.min(canvasHeight, sourceCanvas.height - safeY));

            console.log('Safe coordinates:', { safeX, safeY, safeWidth, safeHeight });

            if (safeWidth === 0 || safeHeight === 0) {
                console.warn('Selection is outside canvas bounds');
                onCancel();
                return;
            }

            // Extract the selected region from the source canvas
            const ctx = sourceCanvas.getContext('2d');
            if (!ctx) {
                throw new Error('Could not get canvas context');
            }

            const imageData = ctx.getImageData(safeX, safeY, safeWidth, safeHeight);

            // Create a new canvas for the selected region
            const selectedCanvas = document.createElement('canvas');
            selectedCanvas.width = safeWidth;
            selectedCanvas.height = safeHeight;

            const selectedCtx = selectedCanvas.getContext('2d');
            if (!selectedCtx) {
                throw new Error('Could not create selection canvas context');
            }

            selectedCtx.putImageData(imageData, 0, 0);

            // Convert selected canvas to blob
            const screenshot = await new Promise<Blob>((resolve, reject) => {
                selectedCanvas.toBlob((blob) => {
                    if (blob) {
                        resolve(blob);
                    } else {
                        reject(new Error('Failed to create blob from canvas'));
                    }
                }, 'image/jpeg', 0.98);
            });

            console.log('Screenshot created successfully');

            // Extract text from the selected area using OCR
            let extractedText = '';
            try {
                extractedText = await performOCR(screenshot, authToken);
            } catch (ocrError) {
                console.error('OCR extraction failed:', ocrError);
            }

            onSelectionComplete(screenshot, extractedText);
        } catch (error) {
            console.error('Failed to process selection:', error);
            onCancel();
        }
    };

    // Render PDF to canvas at specified scale
    const renderPDFToCanvas = async (
        pdfBlob: Blob,
        pageNumber: number,
        canvas: HTMLCanvasElement,
        containerWidth: number,
        containerHeight: number,
        renderScale: number,
        zoomLevel: number = 1.0
    ): Promise<{ offsetX: number; offsetY: number; pageScale: number; viewport: any }> => {
        const pdfData = await pdfBlob.arrayBuffer();
        const pdf = await pdfjs.getDocument({ data: pdfData }).promise;

        if (pageNumber < 1 || pageNumber > pdf.numPages) {
            throw new Error(`Invalid page number: ${pageNumber}`);
        }

        const page = await pdf.getPage(pageNumber);

        // Calculate the scale needed to render the PDF page to match the layout in container
        // We want the same aspect ratio and positioning as in the PDF viewer
        const originalViewport = page.getViewport({ scale: 1 });

        // Calculate scale factors to fit page within container while preserving aspect ratio
        const scaleX = containerWidth / originalViewport.width;
        const scaleY = containerHeight / originalViewport.height;
        let pageScale = Math.min(scaleX, scaleY);

        // Apply zoom level to the page scale
        pageScale *= zoomLevel;

        // Apply the render scale factor for high resolution
        const finalScale = pageScale * renderScale;

        // Create the viewport at this scale
        const viewport = page.getViewport({ scale: finalScale });

        const context = canvas.getContext('2d');
        if (!context) {
            // Return default values if context not available
            return { offsetX: 0, offsetY: 0, pageScale: 1, viewport: originalViewport };
        }

        // Calculate offset to center the page in the canvas
        const offsetX = Math.round((canvas.width - viewport.width) / 2);
        const offsetY = Math.round((canvas.height - viewport.height) / 2);

        // Render the page with anti-aliasing and smooth rendering for quality
        const renderContext = {
            canvasContext: context,
            viewport: viewport,
            transform: [1, 0, 0, 1, offsetX, offsetY],
            intent: 'display' as const
        };

        // Render the page with improved rendering quality
        await page.render(renderContext).promise;

        return { offsetX, offsetY, pageScale, viewport };
    };

    // Perform OCR on the captured image
    const performOCR = async (image: Blob, token: string): Promise<string> => {
        const formData = new FormData();
        formData.append('image', image);

        const response = await fetch('/api/ocr/recognize', {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${token}`
            },
            body: formData,
        });

        if (!response.ok) {
            throw new Error('Failed to recognize text via OCR');
        }

        const data = await response.json();
        return data.text;
    };

    useEffect(() => {
        if (!overlayCanvasRef.current || !startPoint || !currentPoint || !containerRef.current) return;

        const canvas = overlayCanvasRef.current;
        const ctx = canvas.getContext('2d');
        if (!ctx) return;

        // Match the canvas dimensions to the container
        const containerRect = containerRef.current.getBoundingClientRect();
        canvas.width = containerRect.width;
        canvas.height = containerRect.height;

        // Clear canvas
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // Draw selection rectangle
        const x = Math.min(startPoint.x, currentPoint.x);
        const y = Math.min(startPoint.y, currentPoint.y);
        const width = Math.abs(currentPoint.x - startPoint.x);
        const height = Math.abs(currentPoint.y - startPoint.y);

        // Draw semi-transparent overlay
        ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        // Clear selection area
        ctx.clearRect(x, y, width, height);

        // Draw selection border
        ctx.strokeStyle = '#3b82f6';
        ctx.lineWidth = 2;
        ctx.strokeRect(x, y, width, height);

        // Draw corner handles
        const handleSize = 8;
        ctx.fillStyle = '#3b82f6';
        ctx.fillRect(x - handleSize / 2, y - handleSize / 2, handleSize, handleSize);
        ctx.fillRect(x + width - handleSize / 2, y - handleSize / 2, handleSize, handleSize);
        ctx.fillRect(x - handleSize / 2, y + height - handleSize / 2, handleSize, handleSize);
        ctx.fillRect(x + width - handleSize / 2, y + height - handleSize / 2, handleSize, handleSize);
    }, [startPoint, currentPoint, containerRef]);

    return (
        <div
            className="absolute inset-0 z-50 cursor-crosshair bg-white/20"
            onMouseDown={handleMouseDown}
            onMouseMove={handleMouseMove}
            onMouseUp={handleMouseUp}
        >
            <canvas
                ref={overlayCanvasRef}
                className="absolute inset-0 pointer-events-none"
            />
            <div className="absolute top-4 left-1/2 transform -translate-x-1/2 bg-black/75 text-white px-4 py-2 rounded-lg text-sm z-[60]">
                {t('dragToSelect')}
            </div>
        </div>
    );
};