import React, { useCallback, useEffect, useMemo, useState } from "react";
import axios from "axios";
import { notifyError } from "../shared/toast";
import { BOOKING_STATUS, BOOKING_STATUS_LABEL } from "@/shared/status";
import RefreshButton from "./shared/RefreshButton";

// The engagements this organization holds.
//
// A BOOKING is the engagement itself (owner decision, 01/09/2026) — the connection between an
// employer and a helper, a two-year placement, an enrolment — and it opens the moment the member
// enters the chatflow that forms it. A scheduled meeting is optional furniture, which is why this
// screen exists at all: Appointments and the Calendar can only show things with a time, so a
// placement was invisible to the org that made it.
//
// Filtered by STATUS rather than the panel deciding what "booking" counts as. In progress is a
// real number — it says how many conversations are mid-flight — and it belongs beside the agreed
// ones rather than hidden or silently added to them.
const CHIPS = [
    { value: null, label: "All" },
    { value: BOOKING_STATUS.STARTED, label: BOOKING_STATUS_LABEL[BOOKING_STATUS.STARTED] },
    { value: BOOKING_STATUS.CONFIRMED, label: BOOKING_STATUS_LABEL[BOOKING_STATUS.CONFIRMED] },
    { value: BOOKING_STATUS.PENDING, label: BOOKING_STATUS_LABEL[BOOKING_STATUS.PENDING] },
    { value: BOOKING_STATUS.COMPLETED, label: BOOKING_STATUS_LABEL[BOOKING_STATUS.COMPLETED] },
    // Beside Completed rather than folded into it: "finished" and "finished with something to
    // show for it" are different numbers, and an org reading its own month wants them apart.
    { value: BOOKING_STATUS.CLOSED, label: BOOKING_STATUS_LABEL[BOOKING_STATUS.CLOSED] },
    { value: BOOKING_STATUS.CANCELLED, label: BOOKING_STATUS_LABEL[BOOKING_STATUS.CANCELLED] },
];

// The dot on each filter chip. Same idea as Appointments and the Calendar: the colour on the chip
// is the colour the status is drawn in, so the filter doubles as the key.
const CHIP_COLOR = {
    [BOOKING_STATUS.STARTED]:   "var(--amber)",
    [BOOKING_STATUS.CONFIRMED]: "var(--green)",
    [BOOKING_STATUS.PENDING]:   "var(--muted)",
    [BOOKING_STATUS.COMPLETED]: "var(--brand-700, #8f2a3d)",
    // Grey, deliberately: it is finished but nothing was delivered, so it must not read as an
    // achievement next to Completed.
    [BOOKING_STATUS.CLOSED]:    "var(--muted)",
    [BOOKING_STATUS.CANCELLED]: "var(--red)",
};

const BADGE = {
    [BOOKING_STATUS.STARTED]:   "pt-b-amber",
    [BOOKING_STATUS.CONFIRMED]: "pt-b-green",
    [BOOKING_STATUS.PENDING]:   "pt-b-grey",
    [BOOKING_STATUS.COMPLETED]: "pt-b-brand",
    [BOOKING_STATUS.CLOSED]:    "pt-b-grey",
    [BOOKING_STATUS.CANCELLED]: "pt-b-red",
};

const fmtWhen = (iso) => iso
    ? new Date(iso).toLocaleString("en-HK", { weekday: "short", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit" })
    : null;
const fmtDate = (iso) => iso ? new Date(iso).toLocaleDateString("en-HK") : "—";
const fmtHKD = (n) => n == null ? "—" : "HK$ " + Number(n).toLocaleString("en-HK");

const Bookings = ({ onOpenChat }) => {
    const [rows, setRows] = useState([]);
    const [counts, setCounts] = useState({});
    const [status, setStatus] = useState(null);
    const [loading, setLoading] = useState(true);

    // Named, so the header's Refresh has something to call — the fetch was inline in the effect and
    // this screen had no way to re-read itself at all short of reloading the browser.
    const load = useCallback(async () => {
        setLoading(true);
        try {
            const { data } = await axios.get("/booking/list", { params: status ? { status } : {} });
            setRows(data.bookings || []);
            setCounts(data.counts || {});
        } catch (err) {
            notifyError(err?.response?.data?.message || "Could not load bookings.");
        } finally {
            setLoading(false);
        }
    }, [status]);

    useEffect(() => { load(); }, [load]);

    const total = useMemo(
        () => Object.values(counts).reduce((sum, n) => sum + Number(n || 0), 0),
        [counts],
    );

    return (
        <div className="pt-fade-in">
            <div className="pt-card">
                <div className="pt-card-head" style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 12, flexWrap: "wrap" }}>
                    <h3>Bookings {!loading && <span style={{ color: "var(--muted)", fontSize: 13, fontWeight: 500 }}>· {total}</span>}</h3>
                    <div style={{ display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
                    <div className="pt-chipbar" style={{ marginBottom: 0 }}>
                        {CHIPS.map(chip => {
                            const n = chip.value == null ? total : (counts[chip.value] || 0);
                            // A zero chip stays VISIBLE and goes dead: "is anything cancelled?" is a
                            // question the bar should answer without being pressed, and a chip that
                            // disappears reads as a bug rather than as "none".
                            return (
                                <button key={String(chip.value)} type="button" disabled={chip.value != null && !n}
                                    onClick={() => setStatus(chip.value)}
                                    className={"pt-chip" + (status === chip.value ? " on" : "")}>
                                    {chip.value != null && (
                                        <span className="pt-chip-dot" style={{ background: CHIP_COLOR[chip.value] || "var(--brand)" }} />
                                    )}
                                    {chip.label} <span className="pt-chip-n">{n}</span>
                                </button>
                            );
                        })}
                    </div>
                    <RefreshButton onClick={load} />
                    </div>
                </div>
                <div className="pt-card-pad">
                    <table style={{ width: "100%", borderCollapse: "collapse" }}>
                        <thead><tr style={{ borderBottom: "1px solid var(--line)" }}>
                            {["Reference", "Customer", "Service", "Status", "Scheduled", "Price", "Opened", ""].map(h => (
                                <th key={h} style={{ textAlign: "left", padding: "10px 8px", fontSize: 11.5, color: "var(--muted)", fontWeight: 700, textTransform: "uppercase", letterSpacing: ".06em" }}>{h}</th>
                            ))}
                        </tr></thead>
                        <tbody>
                            {loading && <tr><td colSpan={8} style={{ padding: 18, color: "var(--muted)" }}>Loading…</td></tr>}
                            {!loading && rows.length === 0 && (
                                <tr><td colSpan={8} style={{ padding: 18, color: "var(--muted)", fontSize: 13 }}>
                                    {status == null
                                        ? "No bookings yet. One opens the moment somebody starts a chatflow that sells one of your services."
                                        : "Nothing with this status."}
                                </td></tr>
                            )}
                            {rows.map(b => (
                                <tr key={b.id} style={{ borderBottom: "1px solid var(--line)" }}>
                                    <td style={{ padding: "12px 8px", fontFamily: "var(--mono)", fontSize: 12.5 }}>{b.code}</td>
                                    <td style={{ padding: "12px 8px" }}>
                                        <div style={{ fontWeight: 600 }}>{b.customer || "—"}</div>
                                        {b.role ? <div style={{ fontSize: 11.5, color: "var(--muted)" }}>as {b.role}</div> : null}
                                    </td>
                                    <td style={{ padding: "12px 8px", fontSize: 13 }}>{b.service || "—"}</td>
                                    <td style={{ padding: "12px 8px" }}>
                                        <span className={`pt-badge ${BADGE[b.status] || "pt-b-grey"}`} style={{ padding: "3px 10px" }}>
                                            {BOOKING_STATUS_LABEL[b.status] || "—"}
                                        </span>
                                    </td>
                                    {/* Nothing scheduled is the NORMAL shape for a placement or a
                                        contract — it is not a missing value, and saying "—" alone
                                        reads as data that failed to load. */}
                                    <td style={{ padding: "12px 8px", fontSize: 13, color: b.start_time ? "var(--ink)" : "var(--muted)" }}>
                                        {fmtWhen(b.start_time) || "no meeting"}
                                    </td>
                                    <td style={{ padding: "12px 8px", fontFamily: "var(--mono)", fontSize: 12.5 }}>{fmtHKD(b.price)}</td>
                                    <td style={{ padding: "12px 8px", fontSize: 12.5, color: "var(--muted)" }}>{fmtDate(b.created_at)}</td>
                                    <td style={{ padding: "12px 8px", textAlign: "right" }}>
                                        {b.chatroom_id && (
                                            <button type="button" className="pt-btn pt-btn-ghost pt-btn-sm"
                                                onClick={() => onOpenChat && onOpenChat(b.chatroom_id)}>
                                                Open chat
                                            </button>
                                        )}
                                    </td>
                                </tr>
                            ))}
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    );
};

export default Bookings;
