import { useState, type FormEvent } from 'react'
import { Alert } from '@/components/ui/Alert'
import { Button, IconButton } from '@/components/ui/Button'
import { Dialog } from '@/components/ui/Dialog'
import { Toggle } from '@/components/ui/Toggle'
import { errorMessage } from '@/lib/api'
import type { Garden } from '@/lib/gardens'
import {
  useAddShare,
  useDisableShareLink,
  useEnableShareLink,
  useRemoveShare,
  useShareLink,
  useShares,
  useUpdateShareRole,
  type ShareRole,
} from '@/lib/shares'

/**
 * Owner-only: invite an existing account by email (new invites start as
 * viewers — tap the role chip to flip to editor), remove a share, and manage the
 * public read-only link. v1 has no invitation emails; an unknown address gets a
 * friendly "no account with that email".
 */
export function ShareDialog({ 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 [error, setError] = useState<string | null>(null)
  const busy = add.isPending || updateRole.isPending || remove.isPending

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

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

  return (
    <Dialog title={`Share ${garden.name}`} onClose={onClose} busy={busy} width={440}>
      <form onSubmit={onInvite} className="flex gap-2">
        <input
          className="input"
          type="email"
          placeholder="their@email.com"
          aria-label="Invite by email"
          autoComplete="off"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
        />
        <Button type="submit" variant="primary" className="flex-none" disabled={add.isPending || !email.trim()}>
          {add.isPending ? 'Inviting…' : 'Invite'}
        </Button>
      </form>

      {shares.isError && <Alert>Could not load who this garden is shared with.</Alert>}
      {shares.isSuccess && shares.data.length === 0 && (
        <p className="text-[13px] text-ink-mute">Not shared with anyone yet — invites go to existing accounts.</p>
      )}
      {shares.data?.map((sh) => (
        <div key={sh.userId} className="flex items-center gap-2.5 rounded-full border border-divider bg-bg py-1.5 pl-4 pr-1.5">
          <span className="min-w-0 truncate text-[13px] font-semibold" title={`${sh.displayName} · ${sh.email}`}>
            {sh.email}
          </span>
          <button
            type="button"
            className="tag tag-accent-2 ml-auto cursor-pointer border-0"
            title="Tap to switch between viewer and editor"
            onClick={() => {
              setError(null)
              const role: ShareRole = sh.role === 'viewer' ? 'editor' : 'viewer'
              updateRole.mutate({ userId: sh.userId, role }, { onError: onMutationError('Could not change that role.') })
            }}
          >
            {sh.role}
          </button>
          <IconButton
            label={`Remove ${sh.displayName}`}
            icon="x"
            iconSize={13}
            variant="plain"
            size={30}
            onClick={() => {
              setError(null)
              remove.mutate(sh.userId, { onError: onMutationError('Could not remove that person.') })
            }}
          />
        </div>
      ))}

      <div className="hr my-0.5" />
      <PublicLinkSection gardenId={garden.id} />

      {error && <Alert>{error}</Alert>}
      <div className="flex justify-end">
        <Button onClick={onClose}>Done</Button>
      </div>
    </Dialog>
  )
}

/** The public read-only link: a toggle, the link itself (tap to copy), and a
 *  way to issue a fresh one that invalidates the old. */
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 may be unavailable (non-secure context); the text is selectable.
    }
  }

  return (
    <>
      <div className="flex items-center gap-2.5">
        <span className="text-[13px] font-semibold">Read-only link</span>
        <span className="text-xs text-ink-mute">anyone with it can look, no account needed</span>
        <Toggle
          className="ml-auto"
          label="Public read-only link"
          on={!!link.data?.enabled}
          disabled={busy}
          onChange={(on) =>
            on ? run(enable.mutateAsync({}), 'Could not create the link.') : run(disable.mutateAsync(), 'Could not turn off the link.')
          }
        />
      </div>
      {link.isError && <Alert>Could not load the public link.</Alert>}
      {error && <Alert>{error}</Alert>}
      {url && (
        <div className="flex items-center gap-2">
          <button
            type="button"
            onClick={copy}
            title="Copy the link"
            className="min-w-0 flex-1 cursor-pointer truncate rounded-full border border-dashed border-divider bg-bg px-3.5 py-2 text-left text-xs text-ink-soft hover:border-accent-400"
          >
            {copied ? 'Copied to the clipboard' : url}
          </button>
          <IconButton label="Copy the link" icon="copy" iconSize={14} onClick={copy} />
          <IconButton
            label="Issue a new link (the old one stops working)"
            icon="refresh-cw"
            iconSize={14}
            disabled={busy}
            onClick={() => run(enable.mutateAsync({ rotate: true }), 'Could not regenerate the link.')}
          />
        </div>
      )}
    </>
  )
}
