'use client'

import { useEffect, useId, useState } from 'react'
import * as Dialog from '@radix-ui/react-dialog'
import { Calendar, Clock, Loader2, X } from 'lucide-react'
import { toast } from 'sonner'
import { cmsApi } from '../lib/api.js'
import { adminPortalContainer } from '../lib/portal-container.js'

export interface SchedulePublishDialogProps {
  collectionSlug: string
  documentId: string
  /** Existing scheduled publish time, if any. */
  scheduledAt?: string | null
  /** Existing scheduled unpublish time, if any. */
  scheduledUnpublishAt?: string | null
  open: boolean
  onClose: () => void
  /** Called with the updated schedule fields after a successful save. */
  onScheduled?: (next: {
    status: string
    scheduledAt: string | null
    scheduledUnpublishAt: string | null
  }) => void
}

/**
 * Convert a Date or ISO string to the `YYYY-MM-DDTHH:mm` shape that the
 * `<input type="datetime-local">` element expects, in the user's local
 * timezone (the input is timezone-naive but we present + parse it as local).
 */
function toLocalDateTimeInput(value: string | Date | null | undefined): string {
  if (!value) return ''
  const d = typeof value === 'string' ? new Date(value) : value
  if (Number.isNaN(d.getTime())) return ''
  const pad = (n: number) => String(n).padStart(2, '0')
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`
}

/** Round "now + 1 hour" to the next quarter-hour for a friendly default. */
function defaultScheduleTime(): string {
  const d = new Date(Date.now() + 60 * 60 * 1000)
  d.setMinutes(Math.ceil(d.getMinutes() / 15) * 15, 0, 0)
  return toLocalDateTimeInput(d)
}

export function SchedulePublishDialog({
  collectionSlug,
  documentId,
  scheduledAt,
  scheduledUnpublishAt,
  open,
  onClose,
  onScheduled,
}: SchedulePublishDialogProps) {
  const [publishAt, setPublishAt] = useState('')
  const [unpublishAt, setUnpublishAt] = useState('')
  const [includeUnpublish, setIncludeUnpublish] = useState(false)
  const [saving, setSaving] = useState(false)
  const [cancelling, setCancelling] = useState(false)
  const publishAtId = useId()
  const unpublishAtId = useId()

  const hasExistingSchedule = Boolean(scheduledAt || scheduledUnpublishAt)

  useEffect(() => {
    if (!open) return
    setPublishAt(scheduledAt ? toLocalDateTimeInput(scheduledAt) : defaultScheduleTime())
    setUnpublishAt(scheduledUnpublishAt ? toLocalDateTimeInput(scheduledUnpublishAt) : '')
    setIncludeUnpublish(Boolean(scheduledUnpublishAt))
  }, [open, scheduledAt, scheduledUnpublishAt])

  async function handleSave() {
    if (!publishAt && !(includeUnpublish && unpublishAt)) {
      toast.error('Pick a publish or unpublish time')
      return
    }

    // datetime-local is parsed by the browser as local time; new Date() on
    // that string respects the user's timezone and serialises to a UTC
    // ISO string the server can compare against `Date.now()` cleanly.
    const publishDate = publishAt ? new Date(publishAt) : null
    const unpublishDate = includeUnpublish && unpublishAt ? new Date(unpublishAt) : null

    if (publishDate && publishDate.getTime() <= Date.now()) {
      toast.error('Publish time must be in the future')
      return
    }
    if (unpublishDate && unpublishDate.getTime() <= Date.now()) {
      toast.error('Unpublish time must be in the future')
      return
    }
    if (publishDate && unpublishDate && unpublishDate <= publishDate) {
      toast.error('Unpublish time must be after publish time')
      return
    }

    setSaving(true)
    const res = await cmsApi<any>(`/collections/${collectionSlug}/${documentId}/schedule`, {
      method: 'POST',
      body: JSON.stringify({
        scheduledAt: publishDate ? publishDate.toISOString() : null,
        scheduledUnpublishAt: unpublishDate ? unpublishDate.toISOString() : null,
      }),
    })
    setSaving(false)
    if (res.error) {
      toast.error(res.error)
      return
    }
    toast.success(publishDate ? 'Publish scheduled' : 'Unpublish scheduled')
    onScheduled?.({
      status: res.data?.status ?? 'SCHEDULED',
      scheduledAt: res.data?.scheduledAt ?? (publishDate ? publishDate.toISOString() : null),
      scheduledUnpublishAt:
        res.data?.scheduledUnpublishAt ?? (unpublishDate ? unpublishDate.toISOString() : null),
    })
    onClose()
  }

  async function handleCancelSchedule() {
    setCancelling(true)
    const res = await cmsApi<any>(`/collections/${collectionSlug}/${documentId}/schedule`, {
      method: 'DELETE',
    })
    setCancelling(false)
    if (res.error) {
      toast.error(res.error)
      return
    }
    toast.success('Schedule cancelled')
    onScheduled?.({
      status: res.data?.status ?? 'DRAFT',
      scheduledAt: null,
      scheduledUnpublishAt: null,
    })
    onClose()
  }

  return (
    <Dialog.Root open={open} onOpenChange={(next) => !next && onClose()}>
      <Dialog.Portal container={adminPortalContainer()}>
        <Dialog.Overlay className="fixed inset-0 z-50 bg-black/40" />
        <Dialog.Content className="bg-card text-card-foreground border-border fixed top-1/2 left-1/2 z-50 w-full max-w-md -translate-x-1/2 -translate-y-1/2 rounded-lg border shadow-xl focus:outline-none">
          <div className="border-border flex items-center justify-between border-b px-4 py-3">
            <div className="flex items-center gap-2">
              <Calendar className="text-muted-foreground h-5 w-5" aria-hidden />
              <Dialog.Title className="text-foreground text-lg font-medium">
                Schedule publishing
              </Dialog.Title>
            </div>
            <Dialog.Close asChild>
              <button
                type="button"
                aria-label="Close dialog"
                className="text-muted-foreground hover:bg-accent hover:text-foreground focus-visible:ring-ring rounded-lg p-1.5 transition-colors focus-visible:ring-2 focus-visible:outline-none"
              >
                <X className="h-5 w-5" aria-hidden />
              </button>
            </Dialog.Close>
          </div>

          <div className="space-y-4 px-4 py-4">
            <div className="space-y-1.5">
              <label htmlFor={publishAtId} className="text-foreground text-sm font-medium">
                Publish at
              </label>
              <div className="relative">
                <Clock
                  className="text-muted-foreground pointer-events-none absolute top-2.5 left-2.5 h-4 w-4"
                  aria-hidden
                />
                <input
                  id={publishAtId}
                  type="datetime-local"
                  value={publishAt}
                  onChange={(e) => setPublishAt(e.target.value)}
                  min={toLocalDateTimeInput(new Date(Date.now() + 60 * 1000))}
                  className="border-input bg-background text-foreground focus:border-ring focus:ring-ring w-full rounded-md border py-2 pr-3 pl-9 text-sm focus:ring-1 focus:outline-none"
                />
              </div>
              <p className="text-muted-foreground text-xs">
                The document will move from DRAFT to PUBLISHED at this time (your local timezone).
              </p>
            </div>

            <label className="text-foreground flex items-center gap-2 text-sm">
              <input
                type="checkbox"
                checked={includeUnpublish}
                onChange={(e) => setIncludeUnpublish(e.target.checked)}
                className="border-input text-primary focus:ring-ring h-4 w-4 rounded"
              />
              Also schedule an unpublish
            </label>

            {includeUnpublish && (
              <div className="space-y-1.5">
                <label htmlFor={unpublishAtId} className="text-foreground text-sm font-medium">
                  Unpublish at
                </label>
                <div className="relative">
                  <Clock
                    className="text-muted-foreground pointer-events-none absolute top-2.5 left-2.5 h-4 w-4"
                    aria-hidden
                  />
                  <input
                    id={unpublishAtId}
                    type="datetime-local"
                    value={unpublishAt}
                    onChange={(e) => setUnpublishAt(e.target.value)}
                    min={publishAt || toLocalDateTimeInput(new Date(Date.now() + 60 * 1000))}
                    className="border-input bg-background text-foreground focus:border-ring focus:ring-ring w-full rounded-md border py-2 pr-3 pl-9 text-sm focus:ring-1 focus:outline-none"
                  />
                </div>
              </div>
            )}
          </div>

          <div className="border-border flex items-center justify-between gap-2 border-t px-4 py-3">
            {hasExistingSchedule ? (
              <button
                type="button"
                onClick={handleCancelSchedule}
                disabled={cancelling || saving}
                className="text-destructive hover:bg-destructive/10 inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium disabled:opacity-50"
              >
                {cancelling ? (
                  <Loader2 className="h-4 w-4 animate-spin" aria-hidden />
                ) : (
                  <X className="h-4 w-4" aria-hidden />
                )}
                Cancel schedule
              </button>
            ) : (
              <span />
            )}
            <div className="flex items-center gap-2">
              <Dialog.Close asChild>
                <button
                  type="button"
                  className="text-foreground hover:bg-accent rounded-md px-3 py-1.5 text-sm"
                >
                  Close
                </button>
              </Dialog.Close>
              <button
                type="button"
                onClick={handleSave}
                disabled={saving || cancelling}
                className="bg-primary text-primary-foreground inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium hover:opacity-90 disabled:opacity-50"
              >
                {saving ? (
                  <Loader2 className="h-4 w-4 animate-spin" aria-hidden />
                ) : (
                  <Calendar className="h-4 w-4" aria-hidden />
                )}
                {hasExistingSchedule ? 'Reschedule' : 'Schedule'}
              </button>
            </div>
          </div>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  )
}
