import { useState, type FormEvent } from 'react'
import { Modal } from '@/components/ui/Modal'
import { Alert } from '@/components/ui/Alert'
import { Button } from '@/components/ui/Button'
import { Select } from '@/components/ui/Select'
import { TextField } from '@/components/ui/TextField'
import { cn } from '@/lib/cn'
import { fieldControlClass } from '@/components/ui/field'
import { errorMessage } from '@/lib/api'
import type { Garden } from '@/lib/gardens'
import {
  useAddShare,
  useDisableShareLink,
  useEnableShareLink,
  useRemoveShare,
  useShareLink,
  useShares,
  useUpdateShareRole,
  type ShareRole,
} from '@/lib/shares'

const roleOptions = [
  { value: 'viewer', label: 'Viewer (read-only)' },
  { value: 'editor', label: 'Editor (can edit)' },
]

/**
 * Owner-only dialog to manage a garden's shares: invite an existing user by
 * email as viewer/editor, change a share's role, or remove it. Targets existing
 * accounts only (v1 has no invitation emails) — an unknown email surfaces a
 * friendly "no account with that email".
 */
export function ShareGardenModal({ garden, onClose }: { garden: Garden; onClose: () => void }) {
  const shares = useShares(garden.id)
  const add = useAddShare(garden.id)
  const updateRole = useUpdateShareRole(garden.id)
  const remove = useRemoveShare(garden.id)

  const [email, setEmail] = useState('')
  const [role, setRole] = useState<ShareRole>('viewer')
  const [error, setError] = useState<string | null>(null)

  async function onInvite(e: FormEvent) {
    e.preventDefault()
    setError(null)
    if (!email.trim()) {
      setError('Enter an email address.')
      return
    }
    try {
      await add.mutateAsync({ email: email.trim(), role })
      setEmail('')
    } catch (err) {
      setError(errorMessage(err, 'Could not share the garden.'))
    }
  }

  const onMutationError = (fallback: string) => (err: unknown) => setError(errorMessage(err, fallback))

  return (
    <Modal title="Share garden" onClose={onClose} busy={add.isPending || updateRole.isPending || remove.isPending}>
      <div className="flex flex-col gap-4">
        <form onSubmit={onInvite} className="flex flex-col gap-2">
          <TextField
            label="Invite by email"
            name="email"
            type="email"
            placeholder="person@example.com"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          />
          <div className="flex items-end gap-2">
            <Select
              label="Role"
              name="role"
              value={role}
              onChange={(e) => setRole(e.target.value as ShareRole)}
              options={roleOptions}
              className="flex-1"
            />
            <Button type="submit" disabled={add.isPending}>
              {add.isPending ? 'Sharing…' : 'Share'}
            </Button>
          </div>
          {error && <Alert>{error}</Alert>}
        </form>

        <div>
          <h3 className="mb-2 text-sm font-medium text-fg">Shared with</h3>
          {shares.isPending && <p className="text-sm text-muted">Loading…</p>}
          {shares.isError && <Alert>Could not load who this garden is shared with.</Alert>}
          {shares.isSuccess && shares.data.length === 0 && (
            <p className="text-sm text-muted">Not shared with anyone yet.</p>
          )}
          <ul className="flex flex-col gap-2">
            {shares.data?.map((sh) => (
              <li key={sh.userId} className="flex items-center gap-2">
                <div className="min-w-0 flex-1">
                  <p className="truncate text-sm font-medium text-fg">{sh.displayName}</p>
                  <p className="truncate text-xs text-muted">{sh.email}</p>
                </div>
                <select
                  value={sh.role}
                  onChange={(e) => {
                    setError(null)
                    updateRole.mutate(
                      { userId: sh.userId, role: e.target.value as ShareRole },
                      { onError: onMutationError('Could not change that role.') },
                    )
                  }}
                  aria-label={`Role for ${sh.displayName}`}
                  className={cn(fieldControlClass, 'w-auto px-2 py-1 text-sm')}
                >
                  <option value="viewer">Viewer</option>
                  <option value="editor">Editor</option>
                </select>
                <button
                  type="button"
                  onClick={() => {
                    setError(null)
                    remove.mutate(sh.userId, { onError: onMutationError('Could not remove that person.') })
                  }}
                  aria-label={`Remove ${sh.displayName}`}
                  className="rounded-md px-2 py-1 text-sm text-muted transition-colors hover:bg-red-500/10 hover:text-red-600 dark:hover:text-red-400"
                >
                  ✕
                </button>
              </li>
            ))}
          </ul>
        </div>

        <PublicLinkSection gardenId={garden.id} />

        <div className="flex justify-end">
          <Button variant="ghost" onClick={onClose}>
            Done
          </Button>
        </div>
      </div>
    </Modal>
  )
}

/** The public read-only link controls: create, copy, regenerate, turn off. */
function PublicLinkSection({ gardenId }: { gardenId: number }) {
  const link = useShareLink(gardenId)
  const enable = useEnableShareLink(gardenId)
  const disable = useDisableShareLink(gardenId)
  const [copied, setCopied] = useState(false)
  const [error, setError] = useState<string | null>(null)

  const token = link.data?.enabled ? link.data.token : undefined
  const url = token ? `${window.location.origin}/g/${token}` : ''
  const busy = link.isPending || enable.isPending || disable.isPending

  const run = (p: Promise<unknown>, fallback: string) => {
    setError(null)
    p.catch((err) => setError(errorMessage(err, fallback)))
  }

  async function copy() {
    if (!url) return
    try {
      await navigator.clipboard.writeText(url)
      setCopied(true)
      window.setTimeout(() => setCopied(false), 1500)
    } catch {
      // Clipboard API may be unavailable (e.g. non-secure context); the field is
      // selectable so the user can still copy manually.
    }
  }

  return (
    <div className="border-t border-border pt-4">
      <h3 className="mb-1 text-sm font-medium text-fg">Public link</h3>
      <p className="mb-2 text-xs text-muted">
        Anyone with the link can view this garden read-only — no account needed.
      </p>

      {link.isError && <Alert>Could not load the public link.</Alert>}
      {error && <Alert>{error}</Alert>}

      {link.isSuccess && !link.data.enabled && (
        <Button onClick={() => run(enable.mutateAsync({}), 'Could not create the link.')} disabled={busy}>
          {enable.isPending ? 'Creating…' : 'Create public link'}
        </Button>
      )}

      {link.isSuccess && link.data.enabled && (
        <div className="flex flex-col gap-2">
          <div className="flex items-center gap-2">
            <input
              readOnly
              value={url}
              onFocus={(e) => e.currentTarget.select()}
              aria-label="Public link URL"
              className={cn(fieldControlClass, 'min-w-0 flex-1 text-sm')}
            />
            <Button variant="ghost" onClick={copy} disabled={!url}>
              {copied ? 'Copied' : 'Copy'}
            </Button>
          </div>
          <div className="flex items-center gap-2">
            <Button
              variant="ghost"
              className="px-2 py-1 text-xs"
              onClick={() => run(enable.mutateAsync({ rotate: true }), 'Could not regenerate the link.')}
              disabled={busy}
              title="Issue a new link and invalidate the old one"
            >
              {enable.isPending ? 'Working…' : 'Regenerate'}
            </Button>
            <Button
              variant="ghost"
              className="px-2 py-1 text-xs text-red-600 dark:text-red-400"
              onClick={() => run(disable.mutateAsync(), 'Could not turn off the link.')}
              disabled={busy}
            >
              Turn off
            </Button>
          </div>
        </div>
      )}
    </div>
  )
}
