import { useMemo, useState } from 'react'
import { format } from 'date-fns'
import { fr } from 'date-fns/locale'
import { supa } from '../lib/supabase'
import { humanize, mutate, run } from '../lib/db'
import { useApp } from '../lib/AppContext'
import { useFeedback } from '../lib/feedback'
import { notifyBug } from '../lib/notify'
import {
  Bug,
  BugSeverity,
  BugStatus,
  BUG_STATUS_LABELS,
  BUG_STATUS_ORDER,
  Pole,
  SEVERITY_HINTS,
  SEVERITY_LABELS,
  SEVERITY_ORDER,
  severityBadge
} from '../lib/types'
import { Badge, Button, Field, Input } from './ui'
import { Modal, ModalActions } from './Modal'
import { Select } from './Select'
import { AssigneePicker, PoleChips } from './people'
import { AttachmentPanel, CommentThread, TimeSection } from './EntityExtras'

interface Draft {
  title: string
  description: string
  severity: BugSeverity
  status: BugStatus
  poles: Pole[]
  assignees: string[]
}

function draftOf(bug: Bug | null): Draft {
  return {
    title: bug?.title ?? '',
    description: bug?.description ?? '',
    severity: bug?.severity ?? 'medium',
    status: bug?.status ?? 'open',
    poles: bug?.poles ?? [],
    assignees: bug?.assignee_ids ?? []
  }
}

export default function BugModal({
  bug,
  projectId,
  onClose,
  onSaved
}: {
  bug: Bug | null
  projectId: string
  onClose: () => void
  onSaved: () => Promise<void> | void
}): JSX.Element {
  const { profile, members, membersLoading, memberById } = useApp()
  const { toast, confirm } = useFeedback()

  const initial = useMemo(() => draftOf(bug), [bug])
  const [d, setD] = useState<Draft>(initial)
  const [busy, setBusy] = useState(false)

  const patch = (p: Partial<Draft>): void => setD((cur) => ({ ...cur, ...p }))
  const dirty = useMemo(() => JSON.stringify(d) !== JSON.stringify(initial), [d, initial])

  const save = async (): Promise<void> => {
    if (!d.title.trim()) {
      toast('Donne un titre au bug.', 'error')
      return
    }
    setBusy(true)
    const payload = {
      project_id: projectId,
      title: d.title.trim(),
      description: d.description.trim() || null,
      severity: d.severity,
      status: d.status,
      poles: d.poles,
      assignee_ids: d.assignees
    }

    try {
      let entityId = bug?.id ?? null
      if (bug) {
        await mutate(supa().from('bugs').update(payload).eq('id', bug.id))
      } else {
        const created = await run<{ id: string }>(
          supa()
            .from('bugs')
            .insert({ ...payload, reporter_id: profile?.id ?? null })
            .select('id')
            .single()
        )
        entityId = created?.id ?? null
      }

      if (entityId) {
        const newPoles = d.poles.filter((p) => !(bug?.poles ?? []).includes(p))
        const newAssignees = d.assignees.filter((a) => !(bug?.assignee_ids ?? []).includes(a))
        if (newPoles.length || newAssignees.length) {
          await notifyBug({
            projectId,
            bugId: entityId,
            title: d.title.trim(),
            members,
            poles: newPoles,
            assigneeIds: newAssignees,
            actorId: profile?.id ?? null,
            isNew: !bug
          })
        }
      }

      await onSaved()
      toast(bug ? 'Bug enregistré.' : 'Bug signalé.', 'success')
      onClose()
    } catch (e) {
      toast(humanize(e), 'error')
    } finally {
      setBusy(false)
    }
  }

  const remove = async (): Promise<void> => {
    if (!bug) return
    const ok = await confirm({
      title: 'Supprimer ce bug ?',
      message: `« ${bug.title} » et tout ce qui y est rattaché (temps, discussion, captures) seront supprimés.`,
      danger: true,
      confirmLabel: 'Supprimer'
    })
    if (!ok) return
    setBusy(true)
    try {
      await mutate(supa().from('bugs').delete().eq('id', bug.id))
      await onSaved()
      toast('Bug supprimé.', 'success')
      onClose()
    } catch (e) {
      toast(humanize(e), 'error')
      setBusy(false)
    }
  }

  /** Passe le bug en résolu en un clic : le geste le plus fréquent. */
  const resolve = async (): Promise<void> => {
    if (!bug) return
    setBusy(true)
    try {
      await mutate(supa().from('bugs').update({ status: 'resolved' }).eq('id', bug.id))
      await onSaved()
      toast('Bug marqué comme résolu.', 'success')
      onClose()
    } catch (e) {
      toast(humanize(e), 'error')
      setBusy(false)
    }
  }

  const reporter = memberById(bug?.reporter_id)
  const subtitle = bug ? (
    <span>
      Signalé {reporter ? `par ${reporter.full_name} ` : ''}
      le {format(new Date(bug.created_at), 'd MMM yyyy', { locale: fr })}
    </span>
  ) : null

  return (
    <Modal
      title={bug ? 'Bug' : 'Signaler un bug'}
      subtitle={subtitle}
      onClose={onClose}
      size="lg"
      dirty={dirty && !busy}
      footer={
        <ModalActions onDelete={bug ? remove : undefined} onCancel={onClose}>
          {bug && bug.status !== 'resolved' && bug.status !== 'closed' && (
            <Button onClick={resolve} disabled={busy}>
              Marquer résolu
            </Button>
          )}
          <Button variant="primary" loading={busy} disabled={!d.title.trim()} onClick={save}>
            {bug ? 'Enregistrer' : 'Signaler'}
          </Button>
        </ModalActions>
      }
    >
      <div className="space-y-4">
        <Field label="Que se passe-t-il ?" required>
          {({ id }) => (
            <Input
              id={id}
              autoFocus
              value={d.title}
              maxLength={160}
              placeholder="Le joueur traverse le mur en sautant contre la porte"
              onChange={(e) => patch({ title: e.target.value })}
            />
          )}
        </Field>

        <Field
          label="Étapes pour reproduire"
          hint="Ce que tu faisais, ce qui devait arriver, ce qui est arrivé. Plus c'est précis, plus c'est vite corrigé."
        >
          {({ id }) => (
            <textarea
              id={id}
              className="input h-28 resize-none"
              value={d.description}
              placeholder={'1. Aller au niveau 2\n2. Sauter contre la porte de droite\n→ Le personnage passe à travers'}
              onChange={(e) => patch({ description: e.target.value })}
            />
          )}
        </Field>

        {/* ---- Sévérité : un seul axe d'importance, expliqué ---- */}
        <div className="grid grid-cols-2 gap-3">
          <Field label="Sévérité" hint={SEVERITY_HINTS[d.severity]}>
            <Select
              value={d.severity}
              onChange={(severity) => patch({ severity })}
              ariaLabel="Sévérité du bug"
              options={SEVERITY_ORDER.map((s) => ({
                value: s,
                label: SEVERITY_LABELS[s],
                hint: SEVERITY_HINTS[s]
              }))}
            />
          </Field>
          <Field label="Statut">
            <Select
              value={d.status}
              onChange={(status) => patch({ status })}
              ariaLabel="Statut du bug"
              options={BUG_STATUS_ORDER.map((s) => ({ value: s, label: BUG_STATUS_LABELS[s] }))}
            />
          </Field>
        </div>

        <div className="flex items-center gap-2">
          <Badge className={severityBadge(d.severity)}>{SEVERITY_LABELS[d.severity]}</Badge>
          <span className="text-xs text-subtle">{SEVERITY_HINTS[d.severity]}</span>
        </div>

        {/* ---- Qui ? ---- */}
        <div className="space-y-3 border-t border-border pt-4">
          <Field
            label={`Pôle(s) concerné(s)${d.poles.length ? ` · ${d.poles.length}` : ''}`}
            hint="Tous les membres du pôle reçoivent une notification."
          >
            <PoleChips
              selected={d.poles}
              onToggle={(p) =>
                patch({
                  poles: d.poles.includes(p) ? d.poles.filter((x) => x !== p) : [...d.poles, p]
                })
              }
            />
          </Field>

          <Field label={`Assigné(s)${d.assignees.length ? ` · ${d.assignees.length}` : ''}`}>
            <AssigneePicker
              members={members}
              loading={membersLoading}
              selected={d.assignees}
              onChange={(assignees) => patch({ assignees })}
              poles={d.poles}
            />
          </Field>
        </div>

        {bug ? (
          <div className="space-y-3 border-t border-border pt-4">
            <AttachmentPanel
              entity={{
                kind: 'bug',
                id: bug.id,
                projectId,
                title: bug.title,
                involvedIds: bug.assignee_ids
              }}
            />
            <TimeSection target={{ kind: 'bug', id: bug.id }} projectId={projectId} />
            <CommentThread
              entity={{
                kind: 'bug',
                id: bug.id,
                projectId,
                title: bug.title,
                involvedIds: [...bug.assignee_ids, ...(bug.reporter_id ? [bug.reporter_id] : [])]
              }}
            />
          </div>
        ) : (
          <p className="rounded-lg border border-dashed border-border px-3 py-2.5 text-xs text-subtle">
            Une fois le bug créé, tu pourras y coller des captures d'écran (Ctrl+V), suivre le temps
            passé et en discuter avec l'équipe.
          </p>
        )}
      </div>
    </Modal>
  )
}
