import { useCallback, useEffect, useRef, useState } from "preact/hooks";
import { DateTime } from "luxon";
import { useFlash } from "../App/FlashContext";
import { useTimezone } from "../App/TimezoneProvider";

type TimeUpdate = {
    year?: number | null;
    month?: number;
    day?: number;
    hour?: number;
    minute?: number;
    second?: number;
};

export const TimeInput = ({ defaultValue, onInput }) => {
    const ref = useRef(null);

    const [timezone] = useTimezone();
    const [time, setTime] = useState(
        defaultValue ? DateTime.fromISO(defaultValue, { zone: "UTC" }) : null,
    );

    const updateTime = useCallback(
        (upd: TimeUpdate) => {
            if (upd === null) {
                setTime(null);
            }

            let newTime = time;
            if (newTime === null) {
                newTime = DateTime.now().setZone("UTC");
            }
            setTime(newTime.setZone(timezone).set(upd).setZone("UTC"));
        },
        [time, timezone],
    );

    useEffect(() => {
        onInput(time?.setZone("UTC").toFormat("yyyy-LL-dd'T'HH:mm:ss"));
    }, [time]);

    const flash = useFlash();

    return (
        <>
            <div
                class={"input"}
                onPaste={(ev) => {
                    ev.preventDefault();
                    const pasteValue = ev.clipboardData.getData("text/plain");
                    let dt = DateTime.fromISO(pasteValue, { zone: timezone });

                    if (dt.isValid) {
                        setTime(dt);
                        return;
                    }

                    dt = DateTime.fromSQL(pasteValue);

                    if (dt.isValid) {
                        setTime(dt);
                        return;
                    }

                    flash({
                        message: "Couldn't parse your clipboard data as a valid date-time",
                        type: "error",
                    });
                }}
            >
                <div style={{ flexGrow: "1" }}>
                    <label>
                        <span class="is-sr-only">Years input</span>
                        <input
                            style={{
                                borderStyle: "none",
                                fontFamily: "monospace",
                                width: "calc(4ch + 4px)",
                                fontSize: "1rem",
                            }}
                            type="text"
                            pattern="\d*"
                            maxlength={4}
                            placeholder="YYYY"
                            value={
                                time
                                    ? time.setZone(timezone).year.toLocaleString("en-US", {
                                          minimumIntegerDigits: 4,
                                          useGrouping: false,
                                      })
                                    : ""
                            }
                            onBlur={(ev) => {
                                ev.currentTarget.value
                                    ? updateTime({
                                          year: parseInt(ev.currentTarget.value),
                                      })
                                    : updateTime(null);
                            }}
                        ></input>{" "}
                    </label>
                    -
                    <label>
                        <span class="is-sr-only">Months input</span>
                        <input
                            style={{
                                borderStyle: "none",
                                fontFamily: "monospace",
                                width: "calc(2ch + 4px)",
                                fontSize: "1rem",
                            }}
                            type="text"
                            pattern="\d*"
                            maxlength={2}
                            placeholder="MM"
                            value={
                                time
                                    ? time.setZone(timezone).month.toLocaleString("en-US", {
                                          minimumIntegerDigits: 2,
                                      })
                                    : ""
                            }
                            onBlur={(ev) => {
                                ev.currentTarget.value
                                    ? updateTime({
                                          month: parseInt(ev.currentTarget.value),
                                      })
                                    : updateTime(null);
                            }}
                        ></input>{" "}
                    </label>
                    -
                    <label>
                        <span class="is-sr-only">Days input</span>
                        <input
                            style={{
                                borderStyle: "none",
                                fontFamily: "monospace",
                                width: "calc(2ch + 4px)",
                                fontSize: "1rem",
                            }}
                            type="text"
                            pattern="\d*"
                            maxlength={2}
                            placeholder="DD"
                            value={
                                time
                                    ? time
                                          .setZone(timezone)
                                          .day.toLocaleString("en-US", { minimumIntegerDigits: 2 })
                                    : ""
                            }
                            onBlur={(ev) => {
                                ev.currentTarget.value
                                    ? updateTime({
                                          day: parseInt(ev.currentTarget.value),
                                      })
                                    : updateTime(null);
                            }}
                        ></input>{" "}
                    </label>
                    <label style={{ marginLeft: "8px" }}>
                        <span class="is-sr-only">Hours input</span>
                        <input
                            style={{
                                borderStyle: "none",
                                fontFamily: "monospace",
                                width: "calc(2ch + 4px)",
                                fontSize: "1rem",
                            }}
                            type="text"
                            pattern="\d*"
                            maxlength={2}
                            placeholder="hh"
                            value={
                                time
                                    ? time
                                          .setZone(timezone)
                                          .hour.toLocaleString("en-US", { minimumIntegerDigits: 2 })
                                    : ""
                            }
                            onBlur={(ev) => {
                                ev.currentTarget.value
                                    ? updateTime({
                                          hour: parseInt(ev.currentTarget.value),
                                      })
                                    : updateTime(null);
                            }}
                        ></input>{" "}
                    </label>
                    :
                    <label>
                        <span class="is-sr-only">Minutes input</span>
                        <input
                            style={{
                                borderStyle: "none",
                                fontFamily: "monospace",
                                width: "calc(2ch + 4px)",
                                fontSize: "1rem",
                            }}
                            type="text"
                            pattern="\d*"
                            maxlength={2}
                            placeholder="mm"
                            value={
                                time
                                    ? time.setZone(timezone).minute.toLocaleString("en-US", {
                                          minimumIntegerDigits: 2,
                                      })
                                    : ""
                            }
                            onBlur={(ev) => {
                                ev.currentTarget.value
                                    ? updateTime({
                                          minute: parseInt(ev.currentTarget.value),
                                      })
                                    : updateTime(null);
                            }}
                        ></input>{" "}
                    </label>
                    :
                    <label>
                        <span class="is-sr-only">Seconds input</span>
                        <input
                            style={{
                                borderStyle: "none",
                                fontFamily: "monospace",
                                width: "calc(2ch + 4px)",
                                fontSize: "1rem",
                            }}
                            type="text"
                            pattern="\d*"
                            maxlength={2}
                            placeholder="ss"
                            value={
                                time
                                    ? time.setZone(timezone).second.toLocaleString("en-US", {
                                          minimumIntegerDigits: 2,
                                      })
                                    : ""
                            }
                            onBlur={(ev) => {
                                ev.currentTarget.value
                                    ? updateTime({
                                          second: parseInt(ev.currentTarget.value),
                                      })
                                    : updateTime(null);
                            }}
                        ></input>{" "}
                    </label>
                </div>
                <button
                    style={{
                        background: "none",
                        border: "none",
                        padding: "1px",
                        marginRight: "-3px",
                    }}
                    onClick={() => {
                        ref.current.showPicker();
                    }}
                >
                    <span class="is-sr-only">Show time picker</span>
                    <span class="icon">
                        <i class="fas fa-calendar"></i>
                    </span>
                </button>
            </div>
            <input
                style={{
                    position: "absolute",
                    left: 0,
                    visibility: "hidden",
                }}
                class={"input"}
                type="datetime-local"
                step="1"
                value={
                    time
                        ? time.toFormat("yyyy-LL-dd'T'HH:mm:ss")
                        : DateTime.now().toFormat("yyyy-LL-dd'T'HH:mm:ss")
                }
                ref={ref}
                onInput={(ev) => {
                    ev.currentTarget.value === ""
                        ? updateTime(null)
                        : setTime(
                              DateTime.fromISO(ev.currentTarget.value, { zone: timezone }).setZone(
                                  "UTC",
                              ),
                          );
                }}
            ></input>
        </>
    );
};
