import React, { FormEventHandler, useCallback, useEffect, useState } from 'react';
import FocusTrap from 'focus-trap-react';
import {
  Box,
  Button,
  Header,
  Icon,
  IconButton,
  Icons,
  Overlay,
  OverlayBackdrop,
  OverlayCenter,
  Spinner,
  Text,
  color,
  config,
} from 'folds';
import { IContent } from 'matrix-js-sdk';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import { stopPropagation } from '../../utils/keyboard';
import { scheduleMessage } from '../../utils/scheduledMessages';

interface ScheduleMessageModalProps {
  roomId: string;
  /** Pre-fill the message body from the composer. Pass null/undefined to open blank. */
  initialBody?: string;
  onScheduled: (delayId: string, sendAt: number, content: IContent) => void;
  onClose: () => void;
}

function formatRelativeTime(ms: number): string {
  const totalSeconds = Math.floor(ms / 1000);
  const hours = Math.floor(totalSeconds / 3600);
  const minutes = Math.floor((totalSeconds % 3600) / 60);
  if (hours > 0 && minutes > 0) return `in ${hours}h ${minutes}m`;
  if (hours > 0) return `in ${hours}h`;
  if (minutes > 0) return `in ${minutes}m`;
  return 'in less than a minute';
}

function formatSendAt(sendAt: Date): string {
  const now = new Date();
  const isToday =
    sendAt.getFullYear() === now.getFullYear() &&
    sendAt.getMonth() === now.getMonth() &&
    sendAt.getDate() === now.getDate();
  const tomorrow = new Date(now);
  tomorrow.setDate(tomorrow.getDate() + 1);
  const isTomorrow =
    sendAt.getFullYear() === tomorrow.getFullYear() &&
    sendAt.getMonth() === tomorrow.getMonth() &&
    sendAt.getDate() === tomorrow.getDate();

  const timeStr = sendAt.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });
  if (isToday) return `Today at ${timeStr}`;
  if (isTomorrow) return `Tomorrow at ${timeStr}`;
  return `${sendAt.toLocaleDateString()} at ${timeStr}`;
}

function toLocalDate(date: Date): string {
  const pad = (n: number) => String(n).padStart(2, '0');
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
}

function toLocalTime(date: Date): string {
  const pad = (n: number) => String(n).padStart(2, '0');
  return `${pad(date.getHours())}:${pad(date.getMinutes())}`;
}

// Shared style for date/time inputs — dark-mode calendar/clock popup via colorScheme.
const pickerInputStyle = (c: typeof color, cfg: typeof config): React.CSSProperties => ({
  background: c.SurfaceVariant.Container,
  color: c.SurfaceVariant.OnContainer,
  border: `${cfg.borderWidth.B300} solid ${c.SurfaceVariant.ContainerLine}`,
  borderRadius: cfg.radii.R300,
  padding: `${cfg.space.S200} ${cfg.space.S300}`,
  fontSize: '0.875rem',
  width: '100%',
  boxSizing: 'border-box',
  outline: 'none',
  fontFamily: 'inherit',
  // Hint browser to render the calendar/clock popup in dark mode
  colorScheme: 'dark',
});

export function ScheduleMessageModal({
  roomId,
  initialBody,
  onScheduled,
  onClose,
}: ScheduleMessageModalProps) {
  const mx = useMatrixClient();
  const [messageText, setMessageText] = useState(initialBody ?? '');
  const [submitting, setSubmitting] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Default: 1 hour from now, rounded to nearest 5 minutes
  const defaultDate = () => {
    const d = new Date(Date.now() + 60 * 60 * 1000);
    d.setSeconds(0, 0);
    d.setMinutes(Math.ceil(d.getMinutes() / 5) * 5);
    return d;
  };

  const def = defaultDate();
  const [dateValue, setDateValue] = useState<string>(() => toLocalDate(def));
  const [timeValue, setTimeValue] = useState<string>(() => toLocalTime(def));

  const getSendAt = useCallback((): Date | null => {
    if (!dateValue || !timeValue) return null;
    const dt = new Date(`${dateValue}T${timeValue}:00`);
    return Number.isNaN(dt.getTime()) ? null : dt;
  }, [dateValue, timeValue]);

  const [preview, setPreview] = useState<{ label: string; relative: string } | null>(null);

  const updatePreview = useCallback(() => {
    const sendAt = getSendAt();
    if (!sendAt) {
      setPreview(null);
      return;
    }
    const diffMs = sendAt.getTime() - Date.now();
    if (diffMs < 60_000) {
      setPreview(null);
      return;
    }
    setPreview({ label: formatSendAt(sendAt), relative: formatRelativeTime(diffMs) });
  }, [getSendAt]);

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

  const handleSubmit: FormEventHandler<HTMLFormElement> = async (e) => {
    e.preventDefault();
    if (submitting) return;

    const sendAt = getSendAt();
    if (!sendAt) {
      setError('Please select a valid date and time.');
      return;
    }
    const diffMs = sendAt.getTime() - Date.now();
    if (diffMs < 60_000) {
      setError('Scheduled time must be at least 1 minute in the future.');
      return;
    }
    if (!messageText.trim()) {
      setError('Please enter a message to schedule.');
      return;
    }

    const content: IContent = { body: messageText.trim(), msgtype: 'm.text' };
    setError(null);
    setSubmitting(true);
    try {
      const delayId = await scheduleMessage(mx, roomId, content, sendAt.getTime());
      onScheduled(delayId, sendAt.getTime(), content);
      onClose();
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to schedule message.');
      setSubmitting(false);
    }
  };

  return (
    <Overlay open backdrop={<OverlayBackdrop />}>
      <OverlayCenter>
        <FocusTrap
          focusTrapOptions={{
            initialFocus: false,
            onDeactivate: onClose,
            clickOutsideDeactivates: true,
            escapeDeactivates: stopPropagation,
          }}
        >
          <Box
            as="form"
            role="dialog"
            aria-modal="true"
            aria-labelledby="schedule-message-title"
            onSubmit={handleSubmit}
            direction="Column"
            style={{
              background: color.Surface.Container,
              borderRadius: config.radii.R400,
              boxShadow: color.Other.Shadow,
              width: '100vw',
              maxWidth: 400,
              overflow: 'hidden',
            }}
          >
            {/* Header */}
            <Header
              variant="Surface"
              size="500"
              style={{
                padding: `0 ${config.space.S200} 0 ${config.space.S400}`,
                borderBottomWidth: config.borderWidth.B300,
              }}
            >
              <Box grow="Yes" alignItems="Center" gap="200">
                <Icon src={Icons.Clock} size="100" />
                <Text id="schedule-message-title" size="H4">
                  Schedule Message
                </Text>
              </Box>
              <IconButton size="300" radii="300" onClick={onClose} aria-label="Close">
                <Icon src={Icons.Cross} />
              </IconButton>
            </Header>

            {/* Body */}
            <Box direction="Column" gap="400" style={{ padding: config.space.S400 }}>
              {/* Message input */}
              <Box direction="Column" gap="100">
                <Text as="label" htmlFor="schedule-message-body" size="L400">
                  Message
                </Text>
                <textarea
                  id="schedule-message-body"
                  rows={3}
                  placeholder="Type your message here…"
                  value={messageText}
                  onChange={(e) => setMessageText(e.target.value)}
                  style={{
                    background: color.SurfaceVariant.Container,
                    color: color.SurfaceVariant.OnContainer,
                    border: `${config.borderWidth.B300} solid ${color.SurfaceVariant.ContainerLine}`,
                    borderRadius: config.radii.R300,
                    padding: `${config.space.S200} ${config.space.S300}`,
                    fontSize: '0.875rem',
                    width: '100%',
                    boxSizing: 'border-box',
                    outline: 'none',
                    resize: 'vertical',
                    fontFamily: 'inherit',
                  }}
                />
              </Box>

              {/* Date + Time pickers */}
              <Box direction="Column" gap="100">
                <Text size="L400">Send at</Text>
                <Box gap="200">
                  <Box direction="Column" gap="100" style={{ flex: 1 }}>
                    <Text as="label" htmlFor="schedule-date" size="T200" style={{ opacity: 0.7 }}>
                      Date
                    </Text>
                    <input
                      id="schedule-date"
                      type="date"
                      value={dateValue}
                      onChange={(e) => setDateValue(e.target.value)}
                      style={pickerInputStyle(color, config)}
                    />
                  </Box>
                  <Box direction="Column" gap="100" style={{ flex: 1 }}>
                    <Text as="label" htmlFor="schedule-time" size="T200" style={{ opacity: 0.7 }}>
                      Time
                    </Text>
                    <input
                      id="schedule-time"
                      type="time"
                      value={timeValue}
                      onChange={(e) => setTimeValue(e.target.value)}
                      style={pickerInputStyle(color, config)}
                    />
                  </Box>
                </Box>
              </Box>

              {/* Preview */}
              {preview ? (
                <Box
                  alignItems="Center"
                  gap="200"
                  style={{
                    padding: `${config.space.S100} ${config.space.S200}`,
                    borderRadius: config.radii.R300,
                    background: color.Primary.Container,
                    border: `1px solid ${color.Primary.ContainerLine}`,
                  }}
                >
                  <Icon
                    src={Icons.Clock}
                    size="100"
                    style={{ color: color.Primary.OnContainer, flexShrink: 0 }}
                  />
                  <Box direction="Column">
                    <Text size="T300" style={{ color: color.Primary.OnContainer }}>
                      {preview.label}
                    </Text>
                    <Text size="T200" style={{ color: color.Primary.OnContainer, opacity: 0.7 }}>
                      {preview.relative}
                    </Text>
                  </Box>
                </Box>
              ) : (
                (dateValue || timeValue) && (
                  <Text size="T200" style={{ color: color.Critical.Main }}>
                    Must be at least 1 minute in the future
                  </Text>
                )
              )}

              {/* Error */}
              {error && (
                <Text size="T300" style={{ color: color.Critical.Main }}>
                  {error}
                </Text>
              )}
            </Box>

            {/* Footer */}
            <Box
              gap="300"
              justifyContent="End"
              style={{
                padding: `${config.space.S200} ${config.space.S400} ${config.space.S400}`,
              }}
            >
              <Button
                type="button"
                variant="Secondary"
                fill="None"
                radii="300"
                onClick={onClose}
                disabled={submitting}
              >
                <Text size="B400">Cancel</Text>
              </Button>
              <Button
                type="submit"
                variant="Primary"
                radii="300"
                disabled={submitting || !preview}
                before={submitting ? <Spinner variant="Primary" size="100" /> : undefined}
              >
                <Text size="B400">Schedule</Text>
              </Button>
            </Box>
          </Box>
        </FocusTrap>
      </OverlayCenter>
    </Overlay>
  );
}
