'use client';

import { useState, useRef } from 'react';
import { BrowserMultiFormatReader, DecodeHintType, BarcodeFormat } from '@zxing/library';
import { scanQr } from '@/modules/sessionModule/qrScan/actions/cameraActions';

type Props = {
  isScanning: boolean;
  setIsScanning: (v: boolean) => void;
  onScanResult?: (result: string) => void;
  onServerResponse?: (message: string) => void;
  onError?: (error: string) => void;
};

export default function ScanCard({ 
  isScanning, 
  setIsScanning, 
  onScanResult, 
  onServerResponse, 
  onError 
}: Props) {
  const [isUploading, setIsUploading] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);

  const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) return;

    setIsUploading(true);

    try {
      // Validasi tipe file yang umum didukung browser untuk decoding
      const supportedTypes = ['image/png', 'image/jpeg', 'image/webp', 'image/jpg', 'image/bmp', 'image/gif'];
      if (file.type && !supportedTypes.includes(file.type)) {
        throw new Error('Unsupported image format');
      }

      // Gunakan Object URL untuk menghindari CORS/tainting dan menjaga orientasi EXIF
      const objectUrl = URL.createObjectURL(file);

      // ZXing hints yang lebih komprehensif untuk meningkatkan keberhasilan decoding
      const hints = new Map();
      hints.set(DecodeHintType.TRY_HARDER, true);
      hints.set(DecodeHintType.PURE_BARCODE, false);
      // Izinkan semua format 2D populer untuk toleransi yang lebih baik
      hints.set(DecodeHintType.POSSIBLE_FORMATS, [
        BarcodeFormat.QR_CODE,
        BarcodeFormat.DATA_MATRIX,
        BarcodeFormat.AZTEC,
        BarcodeFormat.PDF_417,
        BarcodeFormat.MAXICODE,
      ]);

      const codeReader = new BrowserMultiFormatReader(hints);

      let text: string | null = null;

      // 1) Coba langsung dari URL
      try {
        const res1 = await (codeReader as any).decodeFromImageUrl?.(objectUrl);
        if (res1) {
          text = res1.getText();
        }
      } catch {}

      // 2) Enhanced fallback dengan preprocessing gambar
      const tryDecodeFromCanvas = async (img: HTMLImageElement) => {
        const maxDim = 1500; // Tingkatkan resolusi maksimum
        const scale = Math.min(1, maxDim / Math.max(img.naturalWidth || img.width, img.naturalHeight || img.height));
        const baseWidth = Math.max(1, Math.floor((img.naturalWidth || img.width) * scale));
        const baseHeight = Math.max(1, Math.floor((img.naturalHeight || img.height) * scale));

        // Preprocessing function untuk meningkatkan kontras dan kualitas
        const preprocessCanvas = (canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) => {
          const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
          const data = imageData.data;

          // Convert to grayscale dan tingkatkan kontras
          for (let i = 0; i < data.length; i += 4) {
            const gray = Math.round(0.299 * data[i] + 0.587 * data[i + 1] + 0.114 * data[i + 2]);
            
            // Tingkatkan kontras dengan threshold
            const enhanced = gray > 128 ? Math.min(255, gray * 1.2) : Math.max(0, gray * 0.8);
            
            data[i] = enhanced;     // red
            data[i + 1] = enhanced; // green
            data[i + 2] = enhanced; // blue
            // alpha tetap sama
          }

          ctx.putImageData(imageData, 0, 0);
        };

        // Coba berbagai rotasi dan preprocessing
        const angles = [0, 90, 180, 270, 45, 135, 225, 315]; // Tambah rotasi diagonal
        for (const angle of angles) {
          const radians = (angle * Math.PI) / 180;
          const canvas = document.createElement('canvas');
          const ctx = canvas.getContext('2d');
          if (!ctx) continue;

          // Hitung dimensi canvas untuk rotasi
          const cos = Math.abs(Math.cos(radians));
          const sin = Math.abs(Math.sin(radians));
          const newWidth = Math.ceil(baseWidth * cos + baseHeight * sin);
          const newHeight = Math.ceil(baseWidth * sin + baseHeight * cos);

          canvas.width = newWidth;
          canvas.height = newHeight;

          ctx.save();
          ctx.translate(canvas.width / 2, canvas.height / 2);
          ctx.rotate(radians);
          ctx.imageSmoothingEnabled = false; // Disable smoothing untuk QR yang tajam
          ctx.drawImage(img, -baseWidth / 2, -baseHeight / 2, baseWidth, baseHeight);
          ctx.restore();

          // Coba decode tanpa preprocessing dulu
          try {
            const resCanvas = await (codeReader as any).decodeFromCanvas?.(canvas);
            if (resCanvas) return resCanvas.getText();
          } catch {}

          // Coba dengan preprocessing
          try {
            preprocessCanvas(canvas, ctx);
            const resCanvas = await (codeReader as any).decodeFromCanvas?.(canvas);
            if (resCanvas) return resCanvas.getText();
          } catch {}

          // Fallback decode dari Image hasil canvas
          try {
            const tmp = new window.Image();
            tmp.src = canvas.toDataURL('image/png');
            await new Promise((resolve, reject) => {
              tmp.onload = resolve;
              tmp.onerror = reject;
              setTimeout(reject, 5000); // timeout 5 detik
            });
            const resImg = await codeReader.decodeFromImage(tmp);
            if (resImg) return resImg.getText();
          } catch {}
        }

        // Coba dengan ukuran berbeda jika masih gagal
        const scales = [0.5, 1.5, 2.0];
        for (const scaleMultiplier of scales) {
          const scaledWidth = Math.floor(baseWidth * scaleMultiplier);
          const scaledHeight = Math.floor(baseHeight * scaleMultiplier);
          
          const canvas = document.createElement('canvas');
          const ctx = canvas.getContext('2d');
          if (!ctx) continue;

          canvas.width = scaledWidth;
          canvas.height = scaledHeight;

          ctx.imageSmoothingEnabled = scaleMultiplier < 1;
          ctx.drawImage(img, 0, 0, scaledWidth, scaledHeight);

          try {
            preprocessCanvas(canvas, ctx);
            const resCanvas = await (codeReader as any).decodeFromCanvas?.(canvas);
            if (resCanvas) return resCanvas.getText();
          } catch {}
        }

        return null;
      };

      if (!text) {
        const img = new window.Image();
        img.crossOrigin = 'anonymous'; // Untuk menghindari CORS issues
        img.src = objectUrl;
        await new Promise((resolve, reject) => {
          img.onload = resolve;
          img.onerror = reject;
          setTimeout(reject, 10000); // timeout 10 detik
        });
        text = await tryDecodeFromCanvas(img);
      }

      // Cleanup object URL
      URL.revokeObjectURL(objectUrl);

      if (!text) throw new Error('QR not detected');
      
      onScanResult?.(text);

      const serverResponse = await scanQr(text);
      if (serverResponse.status === 'success') {
        onServerResponse?.(serverResponse.data);
      } else {
        onError?.(serverResponse.data);
      }
    } catch (err: any) {
      console.error('QR Decode Error:', err);
      if (err?.message === 'Unsupported image format') {
        onError?.('Format gambar tidak didukung. Gunakan PNG, JPEG, WEBP, atau BMP.');
      } else if (err?.message?.includes('timeout')) {
        onError?.('Timeout saat memproses gambar. Coba dengan gambar yang lebih kecil.');
      } else {
        onError?.('Tidak dapat membaca QR code dari gambar. Tips: pastikan gambar jelas, tidak blur, QR code terlihat penuh, dan coba dengan pencahayaan yang baik.');
      }
    } finally {
      setIsUploading(false);
    }
  };

  const handleStartCamera = async () => {
    try {
      if (!('mediaDevices' in navigator) || !navigator.mediaDevices?.getUserMedia) {
        onError?.('Browser tidak mendukung akses kamera.');
        return;
      }

      if (!window.isSecureContext) {
        onError?.('Akses kamera memerlukan konteks aman (HTTPS atau localhost).');
        return;
      }

      const stream = await navigator.mediaDevices.getUserMedia({
        video: { facingMode: 'environment' },
        audio: false,
      });

      // Lepaskan segera; aliran aktual akan ditangani oleh CameraPreview
      stream.getTracks().forEach((track) => track.stop());

      setIsScanning(true);
    } catch (err: any) {
      console.error(err);
      let message = 'Izin kamera ditolak atau perangkat tidak tersedia.';
      if (err?.name === 'NotAllowedError') message = 'Akses kamera ditolak. Mohon izinkan akses kamera.';
      if (err?.name === 'NotFoundError') message = 'Kamera tidak ditemukan pada perangkat ini.';
      if (err?.name === 'OverconstrainedError') message = 'Kamera yang diminta tidak tersedia.';
      onError?.(message);
    }
  };

  const handleStopCamera = () => {
    setIsScanning(false);
  };

  return (
    <div className="bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-2xl p-6 shadow-sm hover:shadow-md transition-shadow">
      <div className="flex items-center mb-6">
        <div className="w-12 h-12 bg-gradient-to-br from-brand-500 to-brand-600 text-white flex items-center justify-center rounded-xl shadow-lg mr-4">
          <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v1m6 11h2m-6 0h-2v4m0-11v3m0 0h.01M12 12h4.01M16 20h4M4 12h4m12 0h4M4 4h4m12 0h4M4 20h4m12 0h4" />
          </svg>
        </div>
        <div>
          <h3 className="text-lg font-semibold text-gray-900 dark:text-white">QR Scanner</h3>
          <p className="text-sm text-gray-500 dark:text-gray-400">
            {isScanning ? 'Camera active' : 'Start scanning'}
          </p>
        </div>
      </div>

      <div className="space-y-3">
        {!isScanning ? (
          <button
            onClick={handleStartCamera}
            className="w-full bg-gradient-to-r from-brand-500 to-brand-600 text-white font-medium py-3 px-4 rounded-xl hover:from-brand-600 hover:to-brand-700 transition-all duration-200 transform hover:scale-[1.02] active:scale-[0.98] shadow-lg"
          >
            Start Camera
          </button>
        ) : (
          <button
            onClick={handleStopCamera}
            className="w-full bg-red-500 text-white font-medium py-3 px-4 rounded-xl hover:bg-red-600 transition-all duration-200 transform hover:scale-[1.02] active:scale-[0.98] shadow-lg"
          >
            Stop Camera
          </button>
        )}

        <div className="relative">
          <div className="absolute inset-0 flex items-center">
            <div className="w-full border-t border-gray-200 dark:border-gray-700" />
          </div>
          <div className="relative flex justify-center text-sm">
            <span className="bg-white dark:bg-gray-900 px-2 text-gray-500 dark:text-gray-400">or</span>
          </div>
        </div>

        <label
          className={`block w-full text-center px-4 py-3 border-2 border-dashed border-gray-300 dark:border-gray-600 text-gray-600 dark:text-gray-400 font-medium rounded-xl cursor-pointer transition-all hover:border-blue-400 hover:text-brand-600 dark:hover:text-brand-400 ${
            isScanning || isUploading ? 'opacity-50 cursor-not-allowed' : ''
          }`}
        >
          {isUploading ? 'Processing...' : 'Upload Image'}
          <input
            ref={fileInputRef}
            type="file"
            accept="image/*"
            className="hidden"
            disabled={isScanning || isUploading}
            onChange={handleFileChange}
          />
        </label>
      </div>

      {isScanning && (
        <div className="mt-4 flex items-center justify-center space-x-2 text-sm text-green-600 dark:text-green-400">
          <div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
          <span>Camera is active</span>
        </div>
      )}
    </div>
  );
}