import React, { useState, useRef, useEffect } from 'react';
import { motion } from 'framer-motion';
import { Header } from './components/Header.jsx';
import { Button } from './components/Button.jsx';
import { PageTransition } from './components/PageTransition.jsx';
import { useNavigate } from 'react-router-dom';
import dutchPlate from './assets/kentekentv.png';
import belgianPlate from './assets/belgischekentekenv2.png';
import germanPlate from './assets/duitskenteken.png';
import dutchFlag from './assets/dutchflag.png';
import belgiumFlag from './assets/belgiumflag.png';
import germanFlag from './assets/duitsevlag.svg';
import logolangLogo from './assets/logolang.png';
import kentekenFontUrl from './assets/Kenteken.ttf';
import { loadCars } from './carStorage.js';

// Browsers assume 96 DPI when printing images on A4 paper. Converting
// centimeters with this resolution ensures the generated plates have the
// intended physical dimensions when downloaded or printed.
export const DEFAULT_DPI = 96;

export function mmToPx(mm, dpi = DEFAULT_DPI) {
  return (mm / 25.4) * dpi;
}

export function cmToPx(cm, dpi = DEFAULT_DPI) {
  return mmToPx(cm * 10, dpi);
}

export default function LicensePlateApp() {
  const [options, setOptions] = useState([]);
  const [plates, setPlates] = useState([]);
  const [previews, setPreviews] = useState([]);
  const frontRefs = useRef([]);
  const rearRefs = useRef([]);
  const navigate = useNavigate();
  const countryOptions = [
    { code: 'NL', label: 'Nederland', flag: dutchFlag, alt: 'Nederlandse vlag' },
    { code: 'BE', label: 'België', flag: belgiumFlag, alt: 'Belgische vlag' },
    { code: 'DE', label: 'Duitsland', flag: germanFlag, alt: 'Duitse vlag' },
  ];

  useEffect(() => {
    loadCars().then((opts) => {
      const sorted = [...opts].sort((a, b) => a.name.localeCompare(b.name));
      setOptions(sorted);
      setPlates([
        {
          carName: sorted[0]?.name || '',
          front: 'AB-123-CD',
          rear: 'AB-123-CD',
          country: 'NL',
        },
      ]);
      setPreviews([{ front: '', rear: '' }]);
    });
  }, []);

  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  const measureTextWidth = (text, size, fontWeightValue) => {
    ctx.font = `${fontWeightValue} ${size}px KentekenFont, monospace`;
    return ctx.measureText(text).width;
  };

  const getFontSize = (text, baseFontSize, maxTextWidth, fontWeightValue) => {
    let size = baseFontSize;
    const processed = text.replace(/ /g, '\u00A0');
    while (
      measureTextWidth(processed, size, fontWeightValue) > maxTextWidth &&
      size > 1
    ) {
      size -= 1;
    }
    return size;
  };

  const svgToPng = async (svg) => {
    if (!svg) return '';
    await document.fonts.ready;
    const clone = svg.cloneNode(true);
    const images = clone.querySelectorAll('image');
    await Promise.all(
      Array.from(images).map(async (img) => {
        const href = img.getAttribute('href');
        const response = await fetch(href);
        const blob = await response.blob();
        const dataUrl = await new Promise((resolve) => {
          const reader = new FileReader();
          reader.onloadend = () => resolve(reader.result);
          reader.readAsDataURL(blob);
        });
        img.setAttribute('href', dataUrl);
      })
    );
    const fontResponse = await fetch(kentekenFontUrl);
    const fontBlob = await fontResponse.blob();
    const fontDataUrl = await new Promise((resolve) => {
      const reader = new FileReader();
      reader.onloadend = () => resolve(reader.result);
      reader.readAsDataURL(fontBlob);
    });
    const style = document.createElement('style');
    style.textContent = `@font-face { font-family: 'KentekenFont'; src: url(${fontDataUrl}) format('truetype'); }`;
    clone.insertBefore(style, clone.firstChild);
    const xml = new XMLSerializer().serializeToString(clone);
    const svg64 = btoa(unescape(encodeURIComponent(xml)));
    const image64 = `data:image/svg+xml;base64,${svg64}`;
    return await new Promise((resolve) => {
      const imgEl = new Image();
      imgEl.onload = () => {
        const canvas = document.createElement('canvas');
        canvas.width = imgEl.width;
        canvas.height = imgEl.height;
        const ctx = canvas.getContext('2d');
        ctx.drawImage(imgEl, 0, 0);
        resolve(canvas.toDataURL('image/png'));
      };
      imgEl.src = image64;
    });
  };

  const downloadCombinedPlates = async () => {
    const frontUrls = [];
    const rearUrls = [];
    const dims = [];
    for (let i = 0; i < plates.length; i++) {
      const car =
        options.find((o) => o.name === plates[i].carName) || options[0];
      const hasRear = car.rearWidth && car.rearHeight;
      const frontWidth = cmToPx(car.width);
      const frontHeight = cmToPx(car.height);
      const rearWidth = hasRear ? cmToPx(car.rearWidth) : frontWidth;
      const rearHeight = hasRear ? cmToPx(car.rearHeight) : frontHeight;
      frontUrls.push(await svgToPng(frontRefs.current[i]));
      rearUrls.push(await svgToPng(rearRefs.current[i]));
      dims.push({ frontWidth, frontHeight, rearWidth, rearHeight });
    }

    const a4Width = cmToPx(21);
    const a4Height = cmToPx(29.7);
    const margin = cmToPx(1.5);
    const gap = 15;
    const maxWidth = Math.max(
      ...dims.map((d) => Math.max(d.frontWidth, d.rearWidth))
    );
    const totalHeight = dims.reduce(
      (sum, d) => sum + d.frontHeight + d.rearHeight,
      0
    );
    const nImages = dims.length * 2;
    const scale = Math.min(
      1,
      (a4Width - margin) / maxWidth,
      (a4Height - gap * (nImages - 1)) / totalHeight
    );

    const canvas = document.createElement('canvas');
    canvas.width = a4Width;
    canvas.height = a4Height;
    const ctx = canvas.getContext('2d');

    const loadImage = (url) =>
      new Promise((resolve) => {
        const img = new Image();
        img.onload = () => resolve(img);
        img.src = url;
      });

    let y = 0;
    for (let i = 0; i < plates.length; i++) {
      const fImg = await loadImage(frontUrls[i]);
      ctx.drawImage(
        fImg,
        margin,
        y,
        fImg.width * scale,
        fImg.height * scale
      );
      y += dims[i].frontHeight * scale + gap;
      const rImg = await loadImage(rearUrls[i]);
      ctx.drawImage(
        rImg,
        margin,
        y,
        rImg.width * scale,
        rImg.height * scale
      );
      y += dims[i].rearHeight * scale;
      if (i < plates.length - 1) y += gap;
    }

    const dataUrl = canvas.toDataURL('image/png');
    const a = document.createElement('a');
    a.download = 'kentekens.png';
    a.href = dataUrl;
    a.click();
  };

  const openPrintPreview = async () => {
    const items = [];
    for (let i = 0; i < plates.length; i++) {
      const car =
        options.find((o) => o.name === plates[i].carName) || options[0];
      const hasRear = car.rearWidth && car.rearHeight;
      const frontWidth = car.width * 10;
      const frontHeight = car.height * 10;
      const rearWidth = hasRear ? car.rearWidth * 10 : frontWidth;
      const rearHeight = hasRear ? car.rearHeight * 10 : frontHeight;
      const frontUrl = await svgToPng(frontRefs.current[i]);
      const rearUrl = await svgToPng(rearRefs.current[i]);
      items.push({ src: frontUrl, width: frontWidth, height: frontHeight });
      items.push({ src: rearUrl, width: rearWidth, height: rearHeight });
    }
    navigate('/print', { state: { items } });
  };

  useEffect(() => {
    const renderPreviews = async () => {
      const newPreviews = [];
      for (let i = 0; i < plates.length; i++) {
        const frontUrl = frontRefs.current[i]
          ? await svgToPng(frontRefs.current[i])
          : '';
        const rearUrl = rearRefs.current[i]
          ? await svgToPng(rearRefs.current[i])
          : '';
        newPreviews.push({ front: frontUrl, rear: rearUrl });
      }
      setPreviews(newPreviews);
    };
    renderPreviews();
  }, [plates, options]);

  const addPlate = () => {
    setPlates((pls) => [
      ...pls,
      {
        carName: options[0]?.name || '',
        front: 'AB-123-CD',
        rear: 'AB-123-CD',
        country: 'NL',
      },
    ]);
    setPreviews((prv) => [...prv, { front: '', rear: '' }]);
  };

  const updatePlate = (index, field, value) => {
    setPlates((pls) => {
      const updated = [...pls];
      updated[index] = { ...updated[index], [field]: value };
      return updated;
    });
  };

  const removePlate = (index) => {
    setPlates((pls) => pls.filter((_, i) => i !== index));
    setPreviews((prv) => prv.filter((_, i) => i !== index));
    frontRefs.current.splice(index, 1);
    rearRefs.current.splice(index, 1);
  };

  return (
    <PageTransition>
      <Header
        count={options.length}
        onRestart={() => window.location.reload()}
        onHome={() => navigate('/')}
      />
      <div className="container dashboard">
        <div className="card">
          {plates.map((plate, i) => {
            const car = options.find((o) => o.name === plate.carName) || options[0];
            const hasRear = car.rearWidth && car.rearHeight;
            const frontWidth = cmToPx(car.width);
            const frontHeight = cmToPx(car.height);
            const rearWidthPx = hasRear ? cmToPx(car.rearWidth) : frontWidth;
            const rearHeightPx = hasRear ? cmToPx(car.rearHeight) : frontHeight;
            const country = plate.country;
            const countryConfig = {
              NL: {
                baseWidth: 624,
                baseHeight: 139,
                plateImage: dutchPlate,
                flag: dutchFlag,
                euWidthRatio: 0.096,
                fontWeight: 'bold',
                textColor: '#000',
                shadowColor: '#ffeb3b',
                dropShadow: { dx: 3, dy: 3, stdDeviation: 1 },
                hasBottomBar: true,
                allowsCentering: true,
              },
              BE: {
                baseWidth: 1848,
                baseHeight: 382,
                plateImage: belgianPlate,
                flag: belgiumFlag,
                euWidthRatio: 0.098,
                fontWeight: 'normal',
                textColor: '#a51f1f',
                shadowColor: '#a51f1f',
                dropShadow: { dx: 0.5, dy: 0.5, stdDeviation: 0.2 },
                hasBottomBar: false,
                allowsCentering: true,
              },
              DE: {
                baseWidth: 1668,
                baseHeight: 360,
                plateImage: germanPlate,
                flag: germanFlag,
                euWidthRatio: 0.11,
                fontWeight: 'bold',
                textColor: '#000',
                shadowColor: 'transparent',
                dropShadow: { dx: 0, dy: 0, stdDeviation: 0 },
                hasBottomBar: false,
                allowsCentering: true,
              },
            };
            const selectedCountry = countryConfig[country] || countryConfig.NL;
            const {
              baseWidth,
              baseHeight,
              plateImage,
              euWidthRatio,
              fontWeight,
              textColor,
              shadowColor,
              dropShadow,
              hasBottomBar,
              allowsCentering,
            } = selectedCountry;
            const euWidth = baseWidth * euWidthRatio;
            const baseFontSize = baseHeight * 0.6;
            const blackHeight = hasBottomBar ? baseHeight * 0.1 : 0;
            const logoHeight = blackHeight * 0.9;
            const logoWidth = logoHeight * (1481 / 240);
            const logoX = (baseWidth - logoWidth) / 2;
            const logoY =
              baseHeight - blackHeight + (blackHeight - logoHeight) / 2;
            const maxTextWidth = baseWidth - euWidth - 20;
            const fontWeightValue = fontWeight;
            const textY = hasBottomBar
              ? (baseHeight - blackHeight) / 2
              : baseHeight / 2;
            const maxCenteredTextWidth = baseWidth - 2 * (euWidth + 10);
            const textShadowValue =
              dropShadow.stdDeviation === 0
                ? 'none'
                : `${dropShadow.dx}px ${dropShadow.dy}px ${dropShadow.stdDeviation}px ${shadowColor}`;
            const frontFontSize = getFontSize(
              plate.front,
              baseFontSize,
              maxTextWidth,
              fontWeightValue
            );
            const rearFontSize = getFontSize(
              plate.rear,
              baseFontSize,
              maxTextWidth,
              fontWeightValue
            );
            const frontTextWidth = measureTextWidth(
              plate.front.replace(/ /g, '\u00A0'),
              frontFontSize,
              fontWeightValue
            );
            const rearTextWidth = measureTextWidth(
              plate.rear.replace(/ /g, '\u00A0'),
              rearFontSize,
              fontWeightValue
            );
            const shouldCenterFront =
              allowsCentering && frontTextWidth <= maxCenteredTextWidth;
            const shouldCenterRear =
              allowsCentering && rearTextWidth <= maxCenteredTextWidth;
            const frontTextAnchor =
              allowsCentering && (country === 'BE' || shouldCenterFront)
                ? 'middle'
                : 'start';
            const rearTextAnchor =
              allowsCentering && (country === 'BE' || shouldCenterRear)
                ? 'middle'
                : 'start';
            const frontTextX =
              country === 'BE'
                ? euWidth + (baseWidth - euWidth) / 2
                : shouldCenterFront
                  ? baseWidth / 2
                  : euWidth + 10;
            const rearTextX =
              country === 'BE'
                ? euWidth + (baseWidth - euWidth) / 2
                : shouldCenterRear
                  ? baseWidth / 2
                  : euWidth + 10;
            return (
              <div key={i} className="plate-block">
                <div className="flex-1">
                  <div
                    className="flag-selector mb"
                    role="group"
                    aria-label="Kies land voor kenteken"
                  >
                    {countryOptions.map((option) => (
                      <button
                        key={option.code}
                        type="button"
                        onClick={() => updatePlate(i, 'country', option.code)}
                        className={`flag-option ${
                          country === option.code ? 'selected' : ''
                        }`}
                      >
                        <img src={option.flag} alt={option.alt} />
                        <span>{option.label}</span>
                      </button>
                    ))}
                  </div>
                  <div className="form-row mb">
                    <label htmlFor={`car-${i}`}>Kinderauto:</label>
                    <select
                      id={`car-${i}`}
                      value={plate.carName}
                      onChange={(e) =>
                        updatePlate(i, 'carName', e.target.value)
                      }
                    >
                      {options.map((opt) => (
                        <option key={opt.name} value={opt.name}>
                          {opt.name}
                        </option>
                      ))}
                    </select>
                  </div>
                  <div className="form-row mb">
                    <label htmlFor={`front-${i}`}>{`Kenteken voor ${i + 1}:`}</label>
                    <input
                      id={`front-${i}`}
                      value={plate.front}
                      onChange={(e) =>
                        updatePlate(i, 'front', e.target.value.toUpperCase())
                      }
                      aria-label={`Plate text front ${i + 1}`}
                      className="font-[KentekenFont] uppercase"
                    />
                  </div>
                  <div className="form-row mb">
                    <label htmlFor={`rear-${i}`}>{`Kenteken achter ${i + 1}:`}</label>
                    <input
                      id={`rear-${i}`}
                      value={plate.rear}
                      onChange={(e) =>
                        updatePlate(i, 'rear', e.target.value.toUpperCase())
                      }
                      aria-label={`Plate text rear ${i + 1}`}
                      className="font-[KentekenFont] uppercase"
                    />
                  </div>
                  {plates.length > 1 && (
                    <Button
                      type="button"
                      onClick={() => removePlate(i)}
                      variant="ghost"
                      className="mt"
                    >
                      Verwijder kenteken
                    </Button>
                  )}
                </div>
                <div className="flex-1 flex flex-col items-center">
                  <svg
                    ref={(el) => (frontRefs.current[i] = el)}
                    width={frontWidth}
                    height={frontHeight}
                    className="hidden"
                    viewBox={`0 0 ${baseWidth} ${baseHeight}`}
                  >
                    <image href={plateImage} width={baseWidth} height={baseHeight} />
                    {country === 'NL' && (
                      <>
                        <rect
                          x="0"
                          y={baseHeight - blackHeight}
                          width={baseWidth}
                          height={blackHeight}
                          fill="#000"
                        />
                        <image
                          href={logolangLogo}
                          x={logoX}
                          y={logoY}
                          width={logoWidth}
                          height={logoHeight}
                        />
                      </>
                    )}
                    <text
                      x={frontTextX}
                      y={textY}
                      textAnchor={frontTextAnchor}
                      dominantBaseline="middle"
                      fontFamily="KentekenFont, monospace"
                      fontWeight={fontWeightValue}
                      fontSize={frontFontSize}
                      fill={textColor}
                      xmlSpace="preserve"
                      style={{
                        textShadow: textShadowValue,
                      }}
                    >
                      {plate.front.replace(/ /g, '\u00A0')}
                    </text>
                  </svg>
                  {previews[i] && previews[i].front && (
                    <motion.img
                      src={previews[i].front}
                      alt={`Kenteken voor ${i + 1}`}
                      className="block mt-4 max-w-full h-auto"
                      initial={{ opacity: 0, scale: 0.98 }}
                      animate={{ opacity: 1, scale: 1 }}
                      transition={{ duration: 0.25 }}
                    />
                  )}
                  <svg
                    ref={(el) => (rearRefs.current[i] = el)}
                    width={rearWidthPx}
                    height={rearHeightPx}
                    className="hidden"
                    viewBox={`0 0 ${baseWidth} ${baseHeight}`}
                  >
                    <image href={plateImage} width={baseWidth} height={baseHeight} />
                    {country === 'NL' && (
                      <>
                        <rect
                          x="0"
                          y={baseHeight - blackHeight}
                          width={baseWidth}
                          height={blackHeight}
                          fill="#000"
                        />
                        <image
                          href={logolangLogo}
                          x={logoX}
                          y={logoY}
                          width={logoWidth}
                          height={logoHeight}
                        />
                      </>
                    )}
                    <text
                      x={rearTextX}
                      y={textY}
                      textAnchor={rearTextAnchor}
                      dominantBaseline="middle"
                      fontFamily="KentekenFont, monospace"
                      fontWeight={fontWeightValue}
                      fontSize={rearFontSize}
                      fill={textColor}
                      xmlSpace="preserve"
                      style={{
                        textShadow: textShadowValue,
                      }}
                    >
                      {plate.rear.replace(/ /g, '\u00A0')}
                    </text>
                  </svg>
                  {previews[i] && previews[i].rear && (
                    <motion.img
                      src={previews[i].rear}
                      alt={`Kenteken achter ${i + 1}`}
                      className="block mt-4 max-w-full h-auto"
                      initial={{ opacity: 0, scale: 0.98 }}
                      animate={{ opacity: 1, scale: 1 }}
                      transition={{ duration: 0.25 }}
                    />
                  )}
                </div>
              </div>
            );
          })}
          <Button type="button" onClick={addPlate} variant="primary" className="mt">
            Nog een kenteken
          </Button>
          <div className="button-row">
            <Button type="button" onClick={downloadCombinedPlates} variant="ghost">
              Download kentekens
            </Button>
            <Button type="button" onClick={openPrintPreview} variant="ghost">
              Print kentekens
            </Button>
          </div>
        </div>
      </div>
    </PageTransition>
  );
}
