'use client'

import * as React from 'react'
import type { WebhookEndpointListItem } from '@admin/actions/webhooks'
import {
  createWebhook,
  getWebhookSecret,
  regenerateWebhookSecret,
  sendTestWebhook,
  updateWebhook
} from '@admin/actions/webhooks'
import { Button } from '@admin/components/ui/button'
import { Checkbox } from '@admin/components/ui/checkbox'
import {
  Dialog,
  DialogBody,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle
} from '@admin/components/ui/dialog'
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage
} from '@admin/components/ui/form'
import { Input } from '@admin/components/ui/input'
import { Spinner } from '@admin/components/ui/spinner'
import { Switch } from '@admin/components/ui/switch'
import { webhookEventSources } from '@admin/data/webhook-events'
import { useWebhookSubscriptions } from '@admin/hooks/use-webhooks'
import { standardSchemaResolver } from '@hookform/resolvers/standard-schema'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { useForm } from 'react-hook-form'
import { toast } from 'sonner'
import { z } from 'zod/v3'

const endpointSchema = z.object({
  name: z.string().trim().min(1, 'Name is required').max(200, 'Name is too long'),
  url: z.string().trim().url('Enter a valid URL'),
  enabled: z.boolean(),
  events: z.array(z.string())
})

type EndpointFormValues = z.infer<typeof endpointSchema>

interface WebhookEndpointDialogProps {
  webhook: WebhookEndpointListItem | null
  open: boolean
  onOpenChange: (open: boolean) => void
}

export function WebhookEndpointDialog({ webhook, open, onOpenChange }: WebhookEndpointDialogProps) {
  const queryClient = useQueryClient()
  const isEdit = webhook !== null
  const { data: subscriptions } = useWebhookSubscriptions()
  const subscribedEvents = React.useMemo(
    () =>
      webhook
        ? (subscriptions ?? [])
            .filter((entry) => entry.webhookId === webhook.id)
            .map((entry) => entry.event)
        : [],
    [subscriptions, webhook]
  )
  const [secret, setSecret] = React.useState<string | null>(null)

  const formSources = webhookEventSources.filter((source) => source.kind === 'form')
  const contentSources = webhookEventSources.filter((source) => source.kind !== 'form')

  const form = useForm<EndpointFormValues>({
    resolver: standardSchemaResolver(endpointSchema),
    defaultValues: {
      name: webhook?.name ?? '',
      url: webhook?.url ?? '',
      enabled: webhook?.enabled ?? true,
      events: subscribedEvents
    }
  })
  const events = form.watch('events')

  React.useEffect(() => {
    if (!open) return

    form.reset({
      name: webhook?.name ?? '',
      url: webhook?.url ?? '',
      enabled: webhook?.enabled ?? true,
      events: subscribedEvents
    })
    setSecret(null)
  }, [form, open, subscribedEvents, webhook])

  const saveMutation = useMutation({
    mutationFn: async (values: EndpointFormValues) => {
      const endpointValues = {
        name: values.name,
        url: values.url,
        enabled: values.enabled
      }
      const result = webhook
        ? await updateWebhook(webhook.id, { ...endpointValues, events: values.events })
        : await createWebhook({ ...endpointValues, events: values.events })
      if (!result.success) {
        throw new Error(result.error || 'Failed to save this webhook')
      }

      return result
    },
    onSuccess: async () => {
      toast.success(isEdit ? 'Webhook saved' : 'Webhook created')
      await queryClient.invalidateQueries({ queryKey: ['webhooks'] })
      await queryClient.invalidateQueries({
        queryKey: ['webhook-subscriptions']
      })
      onOpenChange(false)
    },
    onError: (error: Error) => {
      toast.error(error.message || 'Failed to save this webhook')
    }
  })

  const revealSecretMutation = useMutation({
    mutationFn: async () => {
      if (!webhook) throw new Error('Save this webhook first.')
      const result = await getWebhookSecret(webhook.id)
      if (!result.success || !result.secret) {
        throw new Error(result.error || 'Failed to fetch signing secret')
      }

      return result.secret
    },
    onSuccess: (value) => setSecret(value),
    onError: (error: Error) => {
      toast.error(error.message || 'Failed to fetch signing secret')
    }
  })

  const regenerateSecretMutation = useMutation({
    mutationFn: async () => {
      if (!webhook) throw new Error('Save this webhook first.')
      const result = await regenerateWebhookSecret(webhook.id)
      if (!result.success || !result.secret) {
        throw new Error(result.error || 'Failed to regenerate signing secret')
      }

      return result.secret
    },
    onSuccess: (value) => {
      setSecret(value)
      toast.success('Signing secret regenerated')
    },
    onError: (error: Error) => {
      toast.error(error.message || 'Failed to regenerate signing secret')
    }
  })

  const testMutation = useMutation({
    mutationFn: async () => {
      if (!webhook) throw new Error('Save this webhook first.')
      const result = await sendTestWebhook(webhook.id)
      if (!result.success) {
        throw new Error(result.error || 'Test webhook failed')
      }

      return result
    },
    onSuccess: async (result) => {
      toast.success(
        result.statusCode ? `Test delivered (status ${result.statusCode})` : 'Test delivered'
      )
      await queryClient.invalidateQueries({ queryKey: ['webhook-deliveries'] })
    },
    onError: (error: Error) => {
      toast.error(error.message || 'Test webhook failed')
    }
  })

  const isPending = saveMutation.isPending

  function toggleEvent(event: string, checked: boolean) {
    const currentEvents = form.getValues('events')
    const nextEvents = checked
      ? currentEvents.includes(event)
        ? currentEvents
        : [...currentEvents, event]
      : currentEvents.filter((entry) => entry !== event)
    form.setValue('events', nextEvents, { shouldDirty: true, shouldValidate: true })
  }

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="max-w-135">
        <Form {...form}>
          <form
            autoComplete="off"
            onSubmit={form.handleSubmit((values) => saveMutation.mutate(values))}
          >
            <DialogHeader>
              <DialogTitle>{isEdit ? `Edit webhook — ${webhook.name}` : 'Add webhook'}</DialogTitle>
              <DialogDescription>
                Events are delivered as signed JSON POST requests
              </DialogDescription>
            </DialogHeader>

            <DialogBody>
              <div className="space-y-4">
                <FormField
                  control={form.control}
                  name="name"
                  render={({ field }) => (
                    <FormItem>
                      <FormLabel>Name</FormLabel>
                      <FormControl>
                        <Input placeholder="Zapier" disabled={isPending} {...field} />
                      </FormControl>
                      <FormMessage />
                    </FormItem>
                  )}
                />
                <FormField
                  control={form.control}
                  name="url"
                  render={({ field }) => (
                    <FormItem>
                      <FormLabel>URL</FormLabel>
                      <FormControl>
                        <Input
                          type="url"
                          placeholder="https://example.com/webhooks"
                          disabled={isPending}
                          {...field}
                        />
                      </FormControl>
                      <FormMessage />
                    </FormItem>
                  )}
                />
                <FormField
                  control={form.control}
                  name="enabled"
                  render={({ field }) => (
                    <FormItem className="flex items-center justify-between rounded-md border border-border px-3 py-2">
                      <FormLabel>Enabled</FormLabel>
                      <FormControl>
                        <Switch
                          checked={field.value}
                          onCheckedChange={field.onChange}
                          disabled={isPending}
                        />
                      </FormControl>
                    </FormItem>
                  )}
                />
                {isEdit && (
                  <div className="space-y-2 rounded-md border border-border p-3">
                    <p className="text-sm leading-none font-medium">Signing secret</p>
                    <div className="flex items-center gap-2">
                      <span className="min-w-0 flex-1 truncate font-mono text-xs">
                        {secret ?? 'whsec_••••••••••••••••'}
                      </span>
                      <Button
                        type="button"
                        variant="outline"
                        size="sm"
                        disabled={revealSecretMutation.isPending || secret !== null}
                        aria-busy={revealSecretMutation.isPending}
                        onClick={() => revealSecretMutation.mutate()}
                      >
                        {revealSecretMutation.isPending && <Spinner />}
                        {revealSecretMutation.isPending ? 'Revealing…' : 'Reveal'}
                      </Button>
                      <Button
                        type="button"
                        variant="outline"
                        size="sm"
                        disabled={regenerateSecretMutation.isPending}
                        aria-busy={regenerateSecretMutation.isPending}
                        onClick={() => regenerateSecretMutation.mutate()}
                      >
                        {regenerateSecretMutation.isPending && <Spinner />}
                        {regenerateSecretMutation.isPending ? 'Regenerating…' : 'Regenerate'}
                      </Button>
                    </div>
                    <p className="text-xs text-muted-foreground">
                      Requests carry x-webhook-id, x-webhook-timestamp, and an HMAC-SHA256
                      x-webhook-signature of the body.
                    </p>
                  </div>
                )}
                {(formSources.length > 0 || contentSources.length > 0) && (
                  <FormField
                    control={form.control}
                    name="events"
                    render={() => (
                      <React.Fragment>
                        {formSources.length > 0 && (
                          <fieldset className="space-y-2 rounded-md border border-border p-3">
                            <legend className="px-1 text-xs font-medium tracking-wide text-muted-foreground uppercase">
                              Events · Forms
                            </legend>
                            {formSources.flatMap((source) =>
                              source.events.map((event) => (
                                <FormItem key={event} className="flex items-center gap-2 space-y-0">
                                  <FormControl>
                                    <Checkbox
                                      checked={events.includes(event)}
                                      onCheckedChange={(checked) =>
                                        toggleEvent(event, checked === true)
                                      }
                                      disabled={isPending}
                                    />
                                  </FormControl>
                                  <FormLabel className="font-mono text-xs font-normal">
                                    {event}
                                  </FormLabel>
                                </FormItem>
                              ))
                            )}
                          </fieldset>
                        )}
                        {contentSources.length > 0 && (
                          <fieldset className="space-y-2 rounded-md border border-border p-3">
                            <legend className="px-1 text-xs font-medium tracking-wide text-muted-foreground uppercase">
                              Events · Entities
                            </legend>
                            {contentSources.flatMap((source) =>
                              source.events.map((event) => (
                                <FormItem key={event} className="flex items-center gap-2 space-y-0">
                                  <FormControl>
                                    <Checkbox
                                      checked={events.includes(event)}
                                      onCheckedChange={(checked) =>
                                        toggleEvent(event, checked === true)
                                      }
                                      disabled={isPending}
                                    />
                                  </FormControl>
                                  <FormLabel className="font-mono text-xs font-normal">
                                    {event}
                                  </FormLabel>
                                </FormItem>
                              ))
                            )}
                          </fieldset>
                        )}
                      </React.Fragment>
                    )}
                  />
                )}
                {formSources.length === 0 && contentSources.length === 0 && (
                  <p className="text-sm text-muted-foreground">
                    No schemas yet — generate an entity or form schema to subscribe this endpoint to
                    its events.
                  </p>
                )}
              </div>
            </DialogBody>

            <DialogFooter showCloseButton={true}>
              {isEdit && (
                <Button
                  type="button"
                  variant="outline"
                  size="lg"
                  disabled={testMutation.isPending}
                  aria-busy={testMutation.isPending}
                  onClick={() => testMutation.mutate()}
                >
                  {testMutation.isPending && <Spinner />}
                  {testMutation.isPending ? 'Sending test…' : 'Send test'}
                </Button>
              )}
              <Button type="submit" disabled={isPending} aria-busy={isPending} size="lg">
                {isPending && <Spinner />}
                {isPending
                  ? isEdit
                    ? 'Saving webhook…'
                    : 'Creating webhook…'
                  : isEdit
                    ? 'Save webhook'
                    : 'Create webhook'}
              </Button>
            </DialogFooter>
          </form>
        </Form>
      </DialogContent>
    </Dialog>
  )
}
