import AccessTimeOutlined from "@mui/icons-material/AccessTimeOutlined";
import ChevronLeftOutlined from "@mui/icons-material/ChevronLeftOutlined";
import ChevronRightOutlined from "@mui/icons-material/ChevronRightOutlined";
import KeyboardArrowDownOutlined from "@mui/icons-material/KeyboardArrowDownOutlined";
import IconButton from "@mui/material/IconButton";
import MenuItem from "@mui/material/MenuItem";
import Popover from "@mui/material/Popover";
import TextField from "@mui/material/TextField";
import { useEffect, useMemo, useState } from "react";
import { Button } from "@/shared/ui/Button.jsx";
import styles from "@/shared/ui/TimeRangeFilter.module.css";

const emptyRange = { endMs: "", startMs: "" };
const quickRanges = [
    ["近 1 小时", 60 * 60 * 1000],
    ["近 24 小时", 24 * 60 * 60 * 1000],
    ["近 7 天", 7 * 24 * 60 * 60 * 1000],
];
const weekLabels = ["一", "二", "三", "四", "五", "六", "日"];

export function TimeRangeFilter({ className = "", disabled = false, label = "时间", onChange, value }) {
    const range = useMemo(() => normalizeRange(value), [value]);
    const [anchorEl, setAnchorEl] = useState(null);
    const [draft, setDraft] = useState(() => range);
    const [activeField, setActiveField] = useState("start");
    const [viewDate, setViewDate] = useState(() => dateForField(range, "start", new Date()));
    const [error, setError] = useState("");
    const open = Boolean(anchorEl);
    const days = useMemo(() => calendarDays(viewDate), [viewDate]);
    const selectedDate = dateForField(draft, activeField, viewDate);
    const hasRange = Boolean(range.startMs || range.endMs);

    useEffect(() => {
        if (!open) {
            setDraft(range);
            setActiveField("start");
            setViewDate(dateForField(range, "start", new Date()));
            setError("");
        }
    }, [open, range]);

    const displayLabel = useMemo(() => timeRangeLabel(label, range), [label, range]);

    const openPopover = (event) => {
        if (disabled) {
            return;
        }
        setDraft(range);
        setActiveField("start");
        setViewDate(dateForField(range, "start", new Date()));
        setAnchorEl(event.currentTarget);
    };
    const closePopover = () => setAnchorEl(null);
    const applyRange = (nextRange) => {
        onChange(normalizeRange(nextRange));
        setAnchorEl(null);
        setError("");
    };
    const applyQuickRange = (durationMs) => {
        const endMs = new Date().getTime();
        applyRange({ endMs, startMs: endMs - durationMs });
    };
    const activateField = (field) => {
        setActiveField(field);
        setViewDate(dateForField(draft, field, viewDate));
        setError("");
    };
    const changeMonth = (offset) => {
        setViewDate((current) => new Date(current.getFullYear(), current.getMonth() + offset, 1));
    };
    const changeDay = (day) => {
        setDraft((current) => {
            const base = dateForField(current, activeField, viewDate);
            const nextDate = new Date(
                day.getFullYear(),
                day.getMonth(),
                day.getDate(),
                base.getHours(),
                base.getMinutes(),
                0,
                0,
            );
            return setRangeField(current, activeField, nextDate.getTime());
        });
        setViewDate(new Date(day.getFullYear(), day.getMonth(), 1));
    };
    const changeTime = (unit, nextValue) => {
        setDraft((current) => {
            const nextDate = new Date(dateForField(current, activeField, viewDate));
            if (unit === "hour") {
                nextDate.setHours(Number(nextValue));
            } else {
                nextDate.setMinutes(Number(nextValue));
            }
            nextDate.setSeconds(0, 0);
            return setRangeField(current, activeField, nextDate.getTime());
        });
    };
    const clearRange = () => applyRange(emptyRange);
    const submitDraft = (event) => {
        event.preventDefault();
        // Popover content is rendered through a portal, but React still bubbles
        // submit events through the component tree. Stop here so a picker confirm
        // never submits an outer edit drawer before the new range reaches state.
        event.stopPropagation();
        const nextRange = normalizeRange(draft);
        if (nextRange.startMs && nextRange.endMs && nextRange.endMs <= nextRange.startMs) {
            setError("结束时间必须晚于开始时间");
            return;
        }
        applyRange(nextRange);
    };

    return (
        <>
            <Button
                className={[styles.trigger, className].filter(Boolean).join(" ")}
                aria-expanded={open}
                aria-haspopup="dialog"
                disabled={disabled}
                onClick={openPopover}
            >
                <span className={styles.triggerMeta}>
                    <AccessTimeOutlined fontSize="inherit" />
                    <span>{label}</span>
                </span>
                <span className={styles.triggerText}>{hasRange ? displayLabel : "不限"}</span>
                <KeyboardArrowDownOutlined className={styles.triggerChevron} fontSize="small" />
            </Button>
            <Popover
                anchorEl={anchorEl}
                open={open}
                anchorOrigin={{ horizontal: "left", vertical: "bottom" }}
                slotProps={{ paper: { className: styles.paper } }}
                transformOrigin={{ horizontal: "left", vertical: "top" }}
                onClose={closePopover}
            >
                <form className={styles.panel} onSubmit={submitDraft}>
                    <div className={styles.quickRanges}>
                        {quickRanges.map(([quickLabel, durationMs]) => (
                            <Button
                                key={quickLabel}
                                className={styles.quickButton}
                                onClick={() => applyQuickRange(durationMs)}
                            >
                                {quickLabel}
                            </Button>
                        ))}
                    </div>
                    <div className={styles.rangeFields}>
                        <RangeFieldButton
                            active={activeField === "start"}
                            label="开始时间"
                            value={draft.startMs}
                            onClick={() => activateField("start")}
                        />
                        <RangeFieldButton
                            active={activeField === "end"}
                            label="结束时间"
                            value={draft.endMs}
                            onClick={() => activateField("end")}
                        />
                    </div>
                    <div className={styles.calendarHeader}>
                        <IconButton aria-label="上个月" size="small" onClick={() => changeMonth(-1)}>
                            <ChevronLeftOutlined fontSize="small" />
                        </IconButton>
                        <span className={styles.calendarTitle}>{monthTitle(viewDate)}</span>
                        <IconButton aria-label="下个月" size="small" onClick={() => changeMonth(1)}>
                            <ChevronRightOutlined fontSize="small" />
                        </IconButton>
                    </div>
                    <div className={styles.calendarGrid}>
                        {weekLabels.map((weekday) => (
                            <span className={styles.weekday} key={weekday}>
                                {weekday}
                            </span>
                        ))}
                        {days.map((day) => {
                            const isOutside = day.getMonth() !== viewDate.getMonth();
                            const isSelected = sameDay(day, selectedDate) && Boolean(draft[`${activeField}Ms`]);
                            return (
                                <button
                                    className={[
                                        styles.dayButton,
                                        isOutside ? styles.dayOutside : "",
                                        isSelected ? styles.daySelected : "",
                                    ]
                                        .filter(Boolean)
                                        .join(" ")}
                                    key={`${day.getFullYear()}-${day.getMonth()}-${day.getDate()}`}
                                    type="button"
                                    onClick={() => changeDay(day)}
                                >
                                    {day.getDate()}
                                </button>
                            );
                        })}
                    </div>
                    <div className={styles.timeGrid}>
                        <TextField
                            label="时"
                            select
                            size="small"
                            value={String(selectedDate.getHours())}
                            onChange={(event) => changeTime("hour", event.target.value)}
                        >
                            {Array.from({ length: 24 }, (_, hour) => (
                                <MenuItem key={hour} value={String(hour)}>
                                    {pad2(hour)}
                                </MenuItem>
                            ))}
                        </TextField>
                        <TextField
                            label="分"
                            select
                            size="small"
                            value={String(selectedDate.getMinutes())}
                            onChange={(event) => changeTime("minute", event.target.value)}
                        >
                            {Array.from({ length: 60 }, (_, minute) => (
                                <MenuItem key={minute} value={String(minute)}>
                                    {pad2(minute)}
                                </MenuItem>
                            ))}
                        </TextField>
                    </div>
                    {error ? <div className={styles.error}>{error}</div> : null}
                    <div className={styles.actions}>
                        <Button onClick={clearRange}>清空</Button>
                        <Button type="submit" variant="primary">
                            确定
                        </Button>
                    </div>
                </form>
            </Popover>
        </>
    );
}

function RangeFieldButton({ active, label, onClick, value }) {
    return (
        <button
            className={[styles.rangeField, active ? styles.rangeFieldActive : ""].filter(Boolean).join(" ")}
            type="button"
            onClick={onClick}
        >
            <span className={styles.rangeFieldLabel}>{label}</span>
            <span className={styles.rangeFieldValue}>{formatRangePart(value) || "不限"}</span>
        </button>
    );
}

export function normalizeRange(value) {
    return {
        endMs: normalizeMs(value?.endMs),
        startMs: normalizeMs(value?.startMs),
    };
}

export function timeRangeLabel(label, value) {
    const range = normalizeRange(value);
    if (!range.startMs && !range.endMs) {
        return label;
    }
    return `${formatRangePart(range.startMs) || "不限"} - ${formatRangePart(range.endMs) || "不限"}`;
}

export function datetimeTextToMs(value) {
    const trimmed = String(value || "").trim();
    if (!trimmed) {
        return "";
    }
    const match = /^(\d{4})-(\d{2})-(\d{2})[ T](\d{2}):(\d{2})(?::(\d{2}))?$/.exec(trimmed);
    if (!match) {
        return null;
    }
    const [, year, month, day, hour, minute, second = "00"] = match;
    const date = new Date(
        Number(year),
        Number(month) - 1,
        Number(day),
        Number(hour),
        Number(minute),
        Number(second),
        0,
    );
    if (
        date.getFullYear() !== Number(year) ||
        date.getMonth() !== Number(month) - 1 ||
        date.getDate() !== Number(day) ||
        date.getHours() !== Number(hour) ||
        date.getMinutes() !== Number(minute) ||
        date.getSeconds() !== Number(second)
    ) {
        return null;
    }
    return date.getTime();
}

function dateForField(range, field, fallbackDate) {
    const ms = field === "start" ? range.startMs : range.endMs;
    return ms ? new Date(ms) : fallbackDate;
}

function setRangeField(range, field, value) {
    return field === "start" ? { ...range, startMs: value } : { ...range, endMs: value };
}

function calendarDays(viewDate) {
    const firstDay = new Date(viewDate.getFullYear(), viewDate.getMonth(), 1);
    const mondayIndex = (firstDay.getDay() + 6) % 7;
    const start = new Date(firstDay);
    start.setDate(firstDay.getDate() - mondayIndex);

    return Array.from({ length: 42 }, (_, index) => {
        const day = new Date(start);
        day.setDate(start.getDate() + index);
        return day;
    });
}

function sameDay(left, right) {
    return (
        left.getFullYear() === right.getFullYear() &&
        left.getMonth() === right.getMonth() &&
        left.getDate() === right.getDate()
    );
}

function monthTitle(date) {
    return `${date.getFullYear()}年${pad2(date.getMonth() + 1)}月`;
}

function formatRangePart(value) {
    const text = msToDatetimeText(value);
    return text ? text.replace("-", "/").replace("-", "/") : "";
}

function msToDatetimeText(value) {
    const ms = normalizeMs(value);
    if (!ms) {
        return "";
    }
    const date = new Date(ms);
    return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())} ${pad2(date.getHours())}:${pad2(date.getMinutes())}`;
}

function normalizeMs(value) {
    if (value === "" || value === null || value === undefined) {
        return "";
    }
    const number = Number(value);
    return Number.isFinite(number) && number > 0 ? number : "";
}

function pad2(value) {
    return String(value).padStart(2, "0");
}
