import { createEffect, createSignal, For, onMount } from 'solid-js';

import map1920 from '../../assets/map_1920x1080.webp';
import map3840 from '../../assets/map_3840x1440.webp';
import { download } from '../../helpers/download';
import './waterTemperature.css';

type OutputSize = '1920x1080' | '3840x1440';
type WaterArea = 'Jūra' | 'Līcis' | 'Kurzeme' | 'Zemgale' | 'Vidzeme' | 'Latgale';
type RangeValue = { min: string; max: string };

const areas: Array<{ name: WaterArea; x: number; y: number }> = [
    { name: 'Jūra', x: 690, y: 720 },
    { name: 'Līcis', x: 1640, y: 455 },
    { name: 'Kurzeme', x: 1275, y: 785 },
    { name: 'Zemgale', x: 1880, y: 920 },
    { name: 'Vidzeme', x: 2235, y: 525 },
    { name: 'Latgale', x: 2540, y: 985 },
];

const emptyRanges = (): Record<WaterArea, RangeValue> => Object.fromEntries(
    areas.map(({ name }) => [name, { min: '', max: '' }]),
) as Record<WaterArea, RangeValue>;

export function WaterTemperature() {
    const [output, setOutput] = createSignal<OutputSize>('3840x1440');
    const [ranges, setRanges] = createSignal(emptyRanges());
    const [background, setBackground] = createSignal<HTMLImageElement>();
    let canvas!: HTMLCanvasElement;

    const dimensions = () => output() === '3840x1440'
        ? { width: 3840, height: 1440, map: map3840 }
        : { width: 1920, height: 1080, map: map1920 };

    const complete = () => areas.every(({ name }) => ranges()[name].min.trim() && ranges()[name].max.trim());

    const updateRange = (name: WaterArea, key: keyof RangeValue, value: string) => {
        setRanges(current => ({ ...current, [name]: { ...current[name], [key]: value } }));
    };

    const loadBackground = () => {
        const image = new Image();
        image.onload = () => setBackground(image);
        image.src = dimensions().map;
    };

    const draw = async () => {
        const image = background();
        if (!canvas || !image) return;
        await Promise.all([
            document.fonts.load('700 90px Monda'),
            document.fonts.load('400 40px Monda'),
        ]);
        const { width, height } = dimensions();
        if (canvas.width !== width) canvas.width = width;
        if (canvas.height !== height) canvas.height = height;
        const ctx = canvas.getContext('2d')!;
        ctx.clearRect(0, 0, width, height);
        ctx.drawImage(image, 0, 0, width, height);
        drawNameplate(ctx, width, height);
        drawRanges(ctx, width, height, ranges());
    };

    onMount(loadBackground);
    createEffect(() => { output(); loadBackground(); });
    createEffect(() => { ranges(); background(); void draw(); });

    const downloadPng = () => {
        if (!complete()) return;
        const size = output();
        canvas.toBlob(blob => blob && download(blob, `udens-temperatura-${size}.png`), 'image/png');
    };

    return <section class="pageWorkspace waterPage">
        <div class="pageHeading waterHeading">
            <div><span class="eyebrow">ĒTERA GRAFIKA</span><h1>Ūdens temperatūra</h1><p>Manuāli ievadi temperatūras diapazonus un sagatavo karti eksportam.</p></div>
            <span class="selectionCount">{complete() ? '6 diapazoni aizpildīti' : `${areas.filter(({ name }) => ranges()[name].min && ranges()[name].max).length} no 6 aizpildīti`}</span>
        </div>

        <section class="waterSetup" aria-labelledby="water-settings">
            <div class="waterOutput">
                <h2 id="water-settings">1. Izvēlies izmēru</h2>
                <div class="resolutionChoices">
                    <button classList={{ active: output() === '1920x1080' }} onClick={() => setOutput('1920x1080')}>1920 × 1080</button>
                    <button classList={{ active: output() === '3840x1440' }} onClick={() => setOutput('3840x1440')}>3840 × 1440</button>
                </div>
            </div>
            <div class="waterFields">
                <h2>2. Ievadi temperatūras</h2>
                <div class="rangeGrid"><For each={areas}>{({ name }) => <fieldset class="rangeField">
                    <legend>{name}</legend>
                    <label><span>No</span><input type="number" step="1" inputmode="numeric" value={ranges()[name].min} onInput={event => updateRange(name, 'min', event.currentTarget.value)} /></label>
                    <span class="rangeSeparator">...</span>
                    <label><span>Līdz</span><input type="number" step="1" inputmode="numeric" value={ranges()[name].max} onInput={event => updateRange(name, 'max', event.currentTarget.value)} /></label>
                </fieldset>}</For></div>
            </div>
        </section>

        <section class="waterPreview">
            <div class="mapToolbar"><div><strong>3. Kartes priekšskatījums</strong><span>{dimensions().width} × {dimensions().height} px eksports</span></div><button class="primary" disabled={!complete()} onClick={downloadPng}>Lejupielādēt PNG</button></div>
            {!complete() && <p class="waterNotice">Aizpildi visus sešus diapazonus, lai lejupielādētu gatavo karti.</p>}
            <div class="canvasFrame"><canvas ref={canvas} width={dimensions().width} height={dimensions().height} /></div>
        </section>
    </section>;
}

function drawRanges(ctx: CanvasRenderingContext2D, width: number, height: number, values: Record<WaterArea, RangeValue>) {
    const scaleX = width / 3840;
    const scaleY = height / 1440;
    // Backgrounds use their target aspect ratio, but production graphics scale
    // uniformly so boxes and type are never stretched vertically or horizontally.
    const graphicScale = scaleX;
    const fontSize = 88 * graphicScale;
    const badgeHeight = 132 * graphicScale;
    const padding = 56 * graphicScale;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.font = `700 ${fontSize}px Monda`;

    areas.forEach(({ name, x, y }) => {
        const range = values[name];
        if (!range.min.trim() || !range.max.trim()) return;
        const text = `${range.min}...${range.max}`;
        const localX = x * scaleX;
        const localY = y * scaleY;
        const badgeWidth = Math.max(300 * scaleX, ctx.measureText(text).width + padding * 2);
        ctx.fillStyle = '#f4f4f4';
        ctx.fillRect(localX - badgeWidth / 2, localY - badgeHeight / 2, badgeWidth, badgeHeight);
        ctx.fillStyle = '#000';
        ctx.fillText(text, localX, localY + 2 * scaleY);
    });
}

function drawNameplate(ctx: CanvasRenderingContext2D, width: number, height: number) {
    const scaleX = width / 3840;
    const scaleY = height / 1440;
    const graphicScale = scaleX;
    const x = 2698 * scaleX;
    const y = 145 * scaleY;
    const titleWidth = 1062 * graphicScale;
    const titleHeight = 124 * graphicScale;
    const sourceWidth = 290 * graphicScale;
    const sourceHeight = 60 * graphicScale;

    ctx.fillStyle = '#8f090b';
    ctx.fillRect(x, y, titleWidth, titleHeight);
    ctx.textAlign = 'left';
    ctx.textBaseline = 'middle';
    ctx.font = `700 ${56 * graphicScale}px Monda`;
    ctx.fillStyle = '#fff';
    ctx.fillText('ŪDENS TEMPERATŪRA', x + 66 * graphicScale, y + titleHeight / 2);

    const sourceX = x + titleWidth - sourceWidth;
    ctx.fillStyle = '#f4f4f4';
    ctx.fillRect(sourceX, y + titleHeight, sourceWidth, sourceHeight);
    ctx.fillStyle = '#000';
    ctx.font = `700 ${39 * graphicScale}px Monda`;
    ctx.textAlign = 'center';
    ctx.fillText('LVĢMC', sourceX + sourceWidth / 2, y + titleHeight + sourceHeight / 2);
}
