import { Component, createEffect, createSignal, onMount, Show } from "solid-js";

import { ResultKeyVal } from "../../consts";
import { WindInputs, WindSignals } from "./WindInputs";

import arrowUrl from "../../assets/arrow.webp";
import { cityCoords } from "../cityCoords";
import { MapResolution, resolutionProps, windProps, WindProps } from "./mapConsts";
import { CityData, drawOnMap } from "./canvasDraw";
import { IconInputs } from "../weatherIcons/IconInputs";
import { preloadWeatherIcons } from "../weatherIcons/weatherIconAssets";
import { download } from '../../helpers/download'
import { faktiskaTemplates } from "../../pages/map-graphics/faktiskaTemplates";
import type { FaktiskaTemplate } from "../../pages/map-graphics/faktiskaTemplates";

export const MapView: Component<{ type: MapResolution, data: () => ResultKeyVal[], mode?: "temperature" | "faktiska", productionTemplate?: boolean, onEditValue?: (city: string, value: string) => void }> = ({ type, data, mode = "temperature", productionTemplate = false, onEditValue }) => {
    const [getCanvas, setCanvas] = createSignal<HTMLCanvasElement>();
    const [getImg, setImg] = createSignal(new Image());
    const [fontReady, setFontReady] = createSignal(false);
    const [iconsReady, setIconsReady] = createSignal(mode !== "faktiska");
    const weatherIconsSignal = createSignal<{[key: string]: string;}>({});
    const [getWeatherIcons] = weatherIconsSignal;
    const [getTitle, setTitle] = createSignal("");
    const [getSource, setSource] = createSignal("");
    
    let lastCoords: CityData[] = [];
    const props = resolutionProps[type];

    // Faktiskā only: click a temperature badge on the map to edit it inline,
    // instead of needing the "Rādīt stacijas" panel for a one-off tweak.
    // Same canvas-coordinate conversion as Brīdinājumi's drag/resize handles
    // (getBoundingClientRect scaling) -- preview-only, this input is a plain
    // DOM element positioned over the canvas and never reaches the export.
    const clickToEditEnabled = mode === "faktiska" && productionTemplate;
    const [hoveredCity, setHoveredCity] = createSignal<string>();
    const [editingCity, setEditingCity] = createSignal<string>();
    const [editValue, setEditValue] = createSignal("");

    const canvasPoint = (event: { clientX: number, clientY: number }) => {
        const canvas = getCanvas()!;
        const rect = canvas.getBoundingClientRect();
        return {
            x: (event.clientX - rect.left) * (canvas.width / rect.width),
            y: (event.clientY - rect.top) * (canvas.height / rect.height),
        };
    };

    const badgeHitTest = (point: { x: number, y: number }): string | undefined => {
        if (!clickToEditEnabled) return undefined;
        const faktiskaTemplate = faktiskaTemplates[type as FaktiskaTemplate];
        const half = faktiskaTemplate.badgeSize / 2;
        for (const [city, marker] of Object.entries(faktiskaTemplate.markers)) {
            if (Math.abs(point.x - marker.x) <= half && Math.abs(point.y - marker.y) <= half) return city;
        }
        return undefined;
    };

    const screenPointFromCanvas = (x: number, y: number) => {
        const canvas = getCanvas()!;
        const rect = canvas.getBoundingClientRect();
        return {
            left: rect.left + x * (rect.width / canvas.width),
            top: rect.top + y * (rect.height / canvas.height),
        };
    };

    const onCanvasPointerMove = (event: PointerEvent) => {
        if (!clickToEditEnabled) return;
        setHoveredCity(badgeHitTest(canvasPoint(event)));
    };

    const onCanvasClick = (event: MouseEvent) => {
        if (!clickToEditEnabled) return;
        const city = badgeHitTest(canvasPoint(event));
        if (!city) return;
        const current = data().find(([c]) => c === city)?.[1];
        setEditValue(typeof current === "number" ? current.toString().replace(".", ",") : "");
        setEditingCity(city);
    };

    const commitEdit = () => {
        const city = editingCity();
        if (city) onEditValue?.(city, editValue());
        setEditingCity(undefined);
    };

    const arrowImg = new Image();
    arrowImg.src = arrowUrl;

    const windSignals: WindSignals = {
        direction: createSignal(""),
        speed: createSignal(""),
        gusts: createSignal(""),
        roundValues: createSignal(mode === "faktiska"),
    }

    function getWindData(): [string, string, string, boolean, WindProps] {
        return [
            windSignals.direction[0](),
            windSignals.speed[0](),
            windSignals.gusts[0](),
            windSignals.roundValues[0](),
            windProps[type],
        ];
    }

    onMount(() => {
        void document.fonts.load(`700 ${props.fontSize}px Monda`).then(() => setFontReady(true));
        if (mode === "faktiska") void preloadWeatherIcons().then(() => setIconsReady(true));
        const ctx = getCanvas()!.getContext("2d")!;
        const img = new Image();
        img.onload = () => {
            setImg(img);
            drawOnMap(
                ctx,
                [img, arrowImg],
                lastCoords,
                getWindData(),
                [getTitle(), getSource()],
                props,
                productionTemplate,
            );
        };
        img.src = props.map;
    });

    createEffect(() => {
        fontReady();
        iconsReady();
        const ctx = getCanvas()!.getContext("2d")!;
        const weatherIcons = getWeatherIcons();
        const coordsAndData: CityData[] = data()
            .map(([city, value]) => [
                city,
                cityCoords[city as keyof typeof cityCoords],
                typeof value === "number" ? value : -99,
                weatherIcons[city],
            ]);
            lastCoords = coordsAndData;
        drawOnMap(
            ctx,
            [getImg(), arrowImg],
            coordsAndData,
            getWindData(),
            [getTitle(), getSource()],
            props,
            productionTemplate,
        );
    });

    const getStyleSize = () => {
        return { "width": "100%", "height": "auto" };
    }

    function downloadPng() {
        const canvas = getCanvas()!;
        if (productionTemplate && (canvas.width !== props.width || canvas.height !== props.height)) {
            console.error(`Faktiskā export blocked: expected ${props.width} × ${props.height}, received ${canvas.width} × ${canvas.height}`);
            return;
        }

        const filename = productionTemplate ? `faktiska-${props.width}x${props.height}.png` : `weather-${type}.png`;
        canvas.toBlob(blob => blob && download(blob, filename), 'image/png')
    }

    return (
        <div class="mapWorkspace">
            <div class="mapToolbar"><div><strong>{productionTemplate ? "Kartes priekšskatījums" : "Map preview"}</strong><span>{props.width} × {props.height} px {productionTemplate ? "eksports" : "export"}</span>{clickToEditEnabled && <span class="mapEditHint">Klikšķini uz temperatūras kartē, lai to mainītu</span>}</div><button class="primary" onClick={downloadPng}>{productionTemplate ? "Lejupielādēt PNG" : "Download PNG"}</button></div>
            <details class="broadcastControls" open={!productionTemplate}>
                <summary><span><strong>{productionTemplate ? "Kartes noformējums" : "Broadcast overlay controls"}</strong>{!productionTemplate && <small>Optional manual wind and weather-symbol overrides</small>}</span></summary>
                {!productionTemplate && <p class="controlHelp">These settings do not change the queried city values. Use them only when preparing a finished broadcast graphic.</p>}
            {!productionTemplate && <div class="overlayFields">
                <label><span>Title</span><input type="text" placeholder="19. APRĪĻA GAISA TEMPERATŪRAS REKORDI" value={getTitle()} onInput={e => setTitle(e.target.value)} /></label>
                <label><span>Source</span><input type="text" placeholder="LVĢMC" value={getSource()} onInput={e => setSource(e.target.value)} /></label>
            </div>}
            <div class="mapControlSections">
                <section class="valueControls">
                    <strong>{productionTemplate ? "Temperatūra un vējš" : "Value and wind settings"}</strong>
                    <div class="windControlRow">
                        <label class="roundControl">
                            <input
                                type="checkbox"
                                checked={windSignals.roundValues[0]()}
                                onChange={e => windSignals.roundValues[1](e.target.checked)}
                            />
                            <span>{productionTemplate ? "Noapaļot temperatūras" : "Round temperatures"}</span>
                        </label>
                        { props.showWind && <WindInputs signals={windSignals} productionTemplate={productionTemplate} /> }
                    </div>
                </section>
                {mode === "faktiska" && <IconInputs cities={data().map(([city]) => city)} weatherIconsSignal={weatherIconsSignal} />}
            </div>
            </details>
            <div class="canvasFrame">
            <canvas
                ref={setCanvas}
                width={props.width}
                height={props.height}
                style={{ ...getStyleSize(), cursor: hoveredCity() ? "pointer" : "default" }}
                onPointerMove={onCanvasPointerMove}
                onPointerLeave={() => setHoveredCity(undefined)}
                onClick={onCanvasClick}
            />
            <Show when={editingCity()}>{city => {
                const marker = () => faktiskaTemplates[type as FaktiskaTemplate].markers[city() as keyof typeof faktiskaTemplates[FaktiskaTemplate]["markers"]];
                const pos = () => screenPointFromCanvas(marker().x, marker().y);
                return <input
                    class="mapValueEditor"
                    ref={el => { setTimeout(() => { el.focus(); el.select(); }, 0); }}
                    style={{ position: "fixed", left: `${pos().left}px`, top: `${pos().top}px`, transform: "translate(-50%, -50%)" }}
                    type="text"
                    inputmode="decimal"
                    value={editValue()}
                    onInput={e => setEditValue(e.currentTarget.value)}
                    onKeyDown={e => {
                        if (e.key === "Enter") commitEdit();
                        if (e.key === "Escape") setEditingCity(undefined);
                    }}
                    onBlur={commitEdit}
                    aria-label={`${city()} temperatūra`}
                />;
            }}</Show>
            </div>
        </div>
    );
}
