import { useEffect, useMemo, useState, type FormEvent } from "react";
import { Bell, CalendarCheck, Check, Clock, Plus, RefreshCw, Send, XCircle } from "lucide-react";
import { Button, hasScope, type ApiSettings, type AuthInfo } from "@govoplan/core-webui";
import {
  closeSchedulingRequest,
  createSchedulingCalendarEvent,
  createSchedulingHolds,
  createSchedulingNotifications,
  createSchedulingRequest,
  decideSchedulingRequest,
  evaluateSchedulingFreeBusy,
  listSchedulingNotifications,
  listSchedulingRequests,
  openSchedulingRequest,
  schedulingSummary,
  type SchedulingNotification,
  type SchedulingRequest,
  type SchedulingSummaryResponse
} from "../../api/scheduling";

type SlotDraft = { label: string; start_at: string; end_at: string };
type ParticipantDraft = { display_name: string; email: string; required: boolean };

const now = new Date();
const defaultStart = new Date(now.getTime() + 24 * 60 * 60 * 1000);
defaultStart.setMinutes(0, 0, 0);
const defaultEnd = new Date(defaultStart.getTime() + 60 * 60 * 1000);

function localValue(date: Date): string {
  const pad = (value: number) => value.toString().padStart(2, "0");
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}T${pad(date.getHours())}:${pad(date.getMinutes())}`;
}

function isoFromLocal(value: string): string {
  return new Date(value).toISOString();
}

export default function SchedulingPage({ settings, auth }: { settings: ApiSettings; auth: AuthInfo }) {
  const [requests, setRequests] = useState<SchedulingRequest[]>([]);
  const [selectedId, setSelectedId] = useState("");
  const [summary, setSummary] = useState<SchedulingSummaryResponse | null>(null);
  const [notifications, setNotifications] = useState<SchedulingNotification[]>([]);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState("");
  const [title, setTitle] = useState("Scheduling poll");
  const [location, setLocation] = useState("");
  const [calendarId, setCalendarId] = useState("");
  const [calendarEnabled, setCalendarEnabled] = useState(false);
  const [slots, setSlots] = useState<SlotDraft[]>([
    { label: "Option 1", start_at: localValue(defaultStart), end_at: localValue(defaultEnd) }
  ]);
  const [participants, setParticipants] = useState<ParticipantDraft[]>([{ display_name: "", email: "", required: true }]);

  const canWrite = hasScope(auth, "scheduling:schedule:write");
  const selected = useMemo(() => requests.find((item) => item.id === selectedId) || requests[0] || null, [requests, selectedId]);
  const optionResultById = useMemo(() => {
    const map = new Map<string, SchedulingSummaryResponse["poll_summary"]["option_results"][number]>();
    for (const result of summary?.poll_summary.option_results || []) map.set(result.option_id, result);
    return map;
  }, [summary]);

  useEffect(() => {
    void loadRequests();
  }, [settings.apiBaseUrl, settings.apiKey, settings.accessToken]);

  useEffect(() => {
    if (!selected?.id) {
      setSummary(null);
      setNotifications([]);
      return;
    }
    void loadDetails(selected.id);
  }, [selected?.id]);

  async function loadRequests() {
    setLoading(true);
    setError("");
    try {
      const response = await listSchedulingRequests(settings);
      setRequests(response.requests);
      if (!selectedId && response.requests[0]) setSelectedId(response.requests[0].id);
    } catch (err) {
      setError(errorMessage(err));
    } finally {
      setLoading(false);
    }
  }

  async function loadDetails(requestId: string) {
    try {
      const [summaryResponse, notificationResponse] = await Promise.all([
        schedulingSummary(settings, requestId).catch(() => null),
        listSchedulingNotifications(settings, requestId).catch(() => ({ notifications: [] }))
      ]);
      setSummary(summaryResponse);
      setNotifications(notificationResponse.notifications);
    } catch (err) {
      setError(errorMessage(err));
    }
  }

  async function createRequest(event: FormEvent) {
    event.preventDefault();
    if (!canWrite) return;
    setSaving(true);
    setError("");
    try {
      const request = await createSchedulingRequest(settings, {
        title,
        location: location || null,
        status: "collecting",
        calendar: {
          enabled: calendarEnabled,
          calendar_id: calendarId || null,
          freebusy_enabled: calendarEnabled,
          tentative_holds_enabled: calendarEnabled,
          create_event_on_decision: calendarEnabled
        },
        slots: slots.map((slot) => ({
          label: slot.label || null,
          start_at: isoFromLocal(slot.start_at),
          end_at: isoFromLocal(slot.end_at),
          location: location || null
        })),
        participants: participants
          .filter((participant) => participant.email || participant.display_name)
          .map((participant) => ({ ...participant, participant_type: "external" }))
      });
      setRequests((items) => [request, ...items]);
      setSelectedId(request.id);
    } catch (err) {
      setError(errorMessage(err));
    } finally {
      setSaving(false);
    }
  }

  async function runAction(action: () => Promise<{ request?: SchedulingRequest } | SchedulingSummaryResponse | unknown>) {
    if (!selected || !canWrite) return;
    setSaving(true);
    setError("");
    try {
      const response = await action();
      const updated = isRequestEnvelope(response) ? response.request : null;
      if (updated) {
        setRequests((items) => items.map((item) => (item.id === updated.id ? updated : item)));
      }
      await loadDetails(selected.id);
    } catch (err) {
      setError(errorMessage(err));
    } finally {
      setSaving(false);
    }
  }

  return (
    <main className="scheduling-page">
      <div className="scheduling-shell">
        <aside className="scheduling-sidebar">
          <div className="scheduling-sidebar-bar">
            <strong>Scheduling</strong>
            <Button className="scheduling-icon-button" onClick={() => void loadRequests()} title="Refresh">
              <RefreshCw size={16} />
            </Button>
          </div>
          <div className="scheduling-list">
            {loading ? <div className="scheduling-note">Loading</div> : null}
            {requests.map((request) => (
              <button
                key={request.id}
                className={`scheduling-list-item ${selected?.id === request.id ? "is-selected" : ""}`}
                type="button"
                onClick={() => setSelectedId(request.id)}
              >
                <span>{request.title}</span>
                <small>{request.status}</small>
              </button>
            ))}
          </div>
        </aside>
        <section className="scheduling-workspace">
          <div className="scheduling-topbar">
            <div className="scheduling-title-line">
              <CalendarCheck size={18} />
              <strong>{selected?.title || "Scheduling"}</strong>
            </div>
            <div className="scheduling-actions">
              <Button disabled={!selected || saving || !canWrite} onClick={() => void runAction(() => openSchedulingRequest(settings, selected!.id))}>
                <Send size={16} /> Open
              </Button>
              <Button disabled={!selected || saving || !canWrite} onClick={() => void runAction(() => closeSchedulingRequest(settings, selected!.id))}>
                <XCircle size={16} /> Close
              </Button>
              <Button disabled={!selected || saving || !canWrite} onClick={() => void runAction(() => evaluateSchedulingFreeBusy(settings, selected!.id))}>
                <RefreshCw size={16} /> Free/busy
              </Button>
              <Button disabled={!selected || saving || !canWrite} onClick={() => void runAction(() => createSchedulingHolds(settings, selected!.id))}>
                <Clock size={16} /> Holds
              </Button>
              <Button disabled={!selected || saving || !canWrite} onClick={() => void runAction(() => createSchedulingCalendarEvent(settings, selected!.id))}>
                <CalendarCheck size={16} /> Event
              </Button>
              <Button disabled={!selected || saving || !canWrite} onClick={() => void runAction(() => createSchedulingNotifications(settings, selected!.id, "reminder"))}>
                <Bell size={16} /> Reminder
              </Button>
            </div>
          </div>

          {error ? <div className="scheduling-alert">{error}</div> : null}

          <div className="scheduling-content">
            <form className="scheduling-create-panel" onSubmit={(event) => void createRequest(event)}>
              <div className="scheduling-panel-heading">
                <Plus size={16} />
                <strong>New poll</strong>
              </div>
              <label>
                <span>Title</span>
                <input value={title} onChange={(event) => setTitle(event.target.value)} />
              </label>
              <label>
                <span>Location</span>
                <input value={location} onChange={(event) => setLocation(event.target.value)} />
              </label>
              <label className="scheduling-checkbox">
                <input checked={calendarEnabled} type="checkbox" onChange={(event) => setCalendarEnabled(event.target.checked)} />
                <span>Calendar</span>
              </label>
              {calendarEnabled ? (
                <label>
                  <span>Calendar ID</span>
                  <input value={calendarId} onChange={(event) => setCalendarId(event.target.value)} />
                </label>
              ) : null}
              <div className="scheduling-form-section">
                <div className="scheduling-mini-heading">
                  <span>Slots</span>
                  <Button type="button" onClick={() => setSlots((items) => [...items, { label: `Option ${items.length + 1}`, start_at: localValue(defaultStart), end_at: localValue(defaultEnd) }])}>
                    <Plus size={14} />
                  </Button>
                </div>
                {slots.map((slot, index) => (
                  <div className="scheduling-slot-draft" key={index}>
                    <input value={slot.label} onChange={(event) => updateSlot(index, "label", event.target.value)} />
                    <input type="datetime-local" value={slot.start_at} onChange={(event) => updateSlot(index, "start_at", event.target.value)} />
                    <input type="datetime-local" value={slot.end_at} onChange={(event) => updateSlot(index, "end_at", event.target.value)} />
                  </div>
                ))}
              </div>
              <div className="scheduling-form-section">
                <div className="scheduling-mini-heading">
                  <span>Participants</span>
                  <Button type="button" onClick={() => setParticipants((items) => [...items, { display_name: "", email: "", required: true }])}>
                    <Plus size={14} />
                  </Button>
                </div>
                {participants.map((participant, index) => (
                  <div className="scheduling-participant-draft" key={index}>
                    <input placeholder="Name" value={participant.display_name} onChange={(event) => updateParticipant(index, "display_name", event.target.value)} />
                    <input placeholder="Email" value={participant.email} onChange={(event) => updateParticipant(index, "email", event.target.value)} />
                  </div>
                ))}
              </div>
              <Button disabled={saving || !canWrite} type="submit" variant="primary">
                <Plus size={16} /> Create
              </Button>
            </form>

            <div className="scheduling-detail">
              {selected ? (
                <>
                  <div className="scheduling-status-row">
                    <span className={`scheduling-status scheduling-status-${selected.status}`}>{selected.status}</span>
                    <span>{selected.participants.length} participants</span>
                    <span>{summary?.poll_summary.response_count || 0} responses</span>
                  </div>
                  <div className="scheduling-slot-table">
                    {selected.slots.map((slot) => {
                      const result = slot.poll_option_id ? optionResultById.get(slot.poll_option_id) : null;
                      return (
                        <div className="scheduling-slot-row" key={slot.id}>
                          <div>
                            <strong>{slot.label}</strong>
                            <small>{formatRange(slot.start_at, slot.end_at)}</small>
                          </div>
                          <span className={`scheduling-freebusy ${slot.freebusy_status || "unknown"}`}>{slot.freebusy_status || "unchecked"}</span>
                          <span>{result?.values.available || 0} yes</span>
                          <span>{result?.values.maybe || 0} maybe</span>
                          <span>{result?.values.unavailable || 0} no</span>
                          <Button disabled={saving || !canWrite} onClick={() => void runAction(() => decideSchedulingRequest(settings, selected.id, { slot_id: slot.id, handoff_to_calendar: selected.create_calendar_event_on_decision }))}>
                            <Check size={16} /> Decide
                          </Button>
                        </div>
                      );
                    })}
                  </div>
                  <div className="scheduling-columns">
                    <div>
                      <div className="scheduling-panel-heading"><strong>Participants</strong></div>
                      {selected.participants.map((participant) => (
                        <div className="scheduling-compact-row" key={participant.id}>
                          <span>{participant.display_name || participant.email || participant.id}</span>
                          <small>{participant.status}</small>
                        </div>
                      ))}
                    </div>
                    <div>
                      <div className="scheduling-panel-heading"><strong>Outbox</strong></div>
                      {notifications.map((notification) => (
                        <div className="scheduling-compact-row" key={notification.id}>
                          <span>{notification.event_kind}</span>
                          <small>{notification.status}</small>
                        </div>
                      ))}
                    </div>
                  </div>
                </>
              ) : (
                <div className="scheduling-empty">No scheduling request</div>
              )}
            </div>
          </div>
        </section>
      </div>
    </main>
  );

  function updateSlot(index: number, field: keyof SlotDraft, value: string) {
    setSlots((items) => items.map((item, itemIndex) => (itemIndex === index ? { ...item, [field]: value } : item)));
  }

  function updateParticipant(index: number, field: keyof ParticipantDraft, value: string) {
    setParticipants((items) => items.map((item, itemIndex) => (itemIndex === index ? { ...item, [field]: value } : item)));
  }
}

function isRequestEnvelope(value: unknown): value is { request: SchedulingRequest } {
  return Boolean(value && typeof value === "object" && "request" in value);
}

function formatRange(start: string, end: string): string {
  const formatter = new Intl.DateTimeFormat(undefined, { dateStyle: "short", timeStyle: "short" });
  return `${formatter.format(new Date(start))} - ${formatter.format(new Date(end))}`;
}

function errorMessage(error: unknown): string {
  return error instanceof Error ? error.message : "Request failed";
}
