"use client";

import clsx from "clsx";
import { useRef, type RefObject } from "react";
import { Plus, Trash2 } from "lucide-react";
import { Field, Input, Select, Textarea } from "@/components/ui/kit";
import type { BotAsset, CustomField, InteractiveAction, InteractiveContent, MediaContent, MediaType, ReplyType, TextContent } from "@/lib/types";
import { AssetUpload } from "./asset-upload";

export type AnyContent = TextContent | MediaContent | InteractiveContent;
export type Errors = Record<string, string>;

export const BUILTIN_VARS = ["first_name", "last_name", "full_name", "phone_number", "email", "country", "language_code"];

export function defaultContent(type: ReplyType): AnyContent {
  if (type === "text") return { body: "" };
  if (type === "media") return { media_type: "image", asset_id: null, caption: "" };
  return { header: { type: "none" }, body: "", footer: "", action: { type: "buttons", buttons: [{ title: "" }] } };
}

function Counter({ value, max }: { value: string | undefined; max: number }) {
  const n = [...(value ?? "")].length;
  return <span className={clsx("tabular text-xs", n > max ? "text-brick" : "text-muted")}>{n}/{max}</span>;
}

/** Clickable {variable} chips that insert at the cursor of the given field. */
export function VariableHints({ target, value, onChange, customFields }: { target: RefObject<HTMLTextAreaElement | HTMLInputElement | null>; value: string; onChange: (v: string) => void; customFields: CustomField[] }) {
  const insert = (key: string) => {
    const el = target.current;
    const token = `{${key}}`;
    if (!el) return onChange(value + token);
    const start = el.selectionStart ?? value.length;
    const end = el.selectionEnd ?? value.length;
    onChange(value.slice(0, start) + token + value.slice(end));
    requestAnimationFrame(() => {
      el.focus();
      el.setSelectionRange(start + token.length, start + token.length);
    });
  };
  return (
    <div className="mt-1.5 flex flex-wrap items-center gap-1">
      <span className="mr-1 text-xs text-muted">Insert</span>
      {[...BUILTIN_VARS, ...customFields.map((f) => f.key)].map((k) => (
        <button key={k} type="button" onClick={() => insert(k)} className="rounded bg-paper px-1.5 py-0.5 font-mono text-[11.5px] text-ink ring-1 ring-inset ring-line hover:bg-teal-soft hover:text-teal">
          {`{${k}}`}
        </button>
      ))}
    </div>
  );
}

function BodyField({ id, label, value, onChange, max, error, customFields, rows = 4, hint }: { id: string; label: string; value: string; onChange: (v: string) => void; max: number; error?: string; customFields: CustomField[]; rows?: number; hint?: string }) {
  const ref = useRef<HTMLTextAreaElement>(null);
  return (
    <Field label={label} htmlFor={id} error={error} hint={hint}>
      <Textarea ref={ref} id={id} rows={rows} value={value} onChange={(e) => onChange(e.target.value)} invalid={!!error} />
      <div className="flex items-start justify-between gap-3">
        <VariableHints target={ref} value={value} onChange={onChange} customFields={customFields} />
        <span className="mt-1.5 shrink-0">
          <Counter value={value} max={max} />
        </span>
      </div>
    </Field>
  );
}

export function TextEditor({ content, onChange, errors, customFields, idPrefix = "rc" }: { content: TextContent; onChange: (c: TextContent) => void; errors: Errors; customFields: CustomField[]; idPrefix?: string }) {
  return <BodyField id={`${idPrefix}-body`} label="Reply text" value={content.body} onChange={(body) => onChange({ body })} max={4096} error={errors.body} customFields={customFields} rows={5} />;
}

export function MediaEditor({
  content,
  onChange,
  errors,
  customFields,
  assets,
  onAsset,
  idPrefix = "rc",
}: {
  content: MediaContent;
  onChange: (c: MediaContent) => void;
  errors: Errors;
  customFields: CustomField[];
  assets: Record<number, BotAsset>;
  onAsset: (a: BotAsset) => void;
  idPrefix?: string;
}) {
  const asset = content.asset_id ? (assets[content.asset_id] ?? null) : null;
  return (
    <div className="space-y-4">
      <Field label="Media type" htmlFor={`${idPrefix}-mt`} error={errors.media_type}>
        <Select
          id={`${idPrefix}-mt`}
          value={content.media_type}
          onChange={(e) => onChange({ ...content, media_type: e.target.value as MediaType, asset_id: null, caption: e.target.value === "audio" ? "" : content.caption })}
        >
          <option value="image">Image</option>
          <option value="video">Video</option>
          <option value="audio">Audio</option>
          <option value="document">Document</option>
        </Select>
      </Field>
      <Field label="File" htmlFor={`${idPrefix}-file`} error={undefined}>
        <AssetUpload
          id={`${idPrefix}-file`}
          key={content.media_type}
          kind={content.media_type}
          asset={asset}
          error={errors.asset_id}
          onChange={(a) => {
            if (a) onAsset(a);
            onChange({ ...content, asset_id: a?.id ?? null });
          }}
        />
      </Field>
      {content.media_type !== "audio" ? (
        <BodyField id={`${idPrefix}-caption`} label="Caption (optional)" value={content.caption ?? ""} onChange={(caption) => onChange({ ...content, caption })} max={1024} error={errors.caption} customFields={customFields} rows={3} />
      ) : (
        <p className="text-[13px] text-muted">WhatsApp audio messages have no caption. Use a text reply alongside if you need words.</p>
      )}
    </div>
  );
}

const ACTIONS: { type: InteractiveAction["type"]; label: string; hint: string }[] = [
  { type: "buttons", label: "Reply buttons", hint: "Up to 3 buttons the customer taps to answer" },
  { type: "cta_url", label: "Link button", hint: "One button that opens a website" },
  { type: "list", label: "List message", hint: "A menu of up to 10 options" },
];

export function InteractiveEditor({
  content,
  onChange,
  errors,
  customFields,
  assets,
  onAsset,
  idPrefix = "rc",
}: {
  content: InteractiveContent;
  onChange: (c: InteractiveContent) => void;
  errors: Errors;
  customFields: CustomField[];
  assets: Record<number, BotAsset>;
  onAsset: (a: BotAsset) => void;
  idPrefix?: string;
}) {
  const a = content.action;
  const set = (patch: Partial<InteractiveContent>) => onChange({ ...content, ...patch });
  const setAction = (action: InteractiveAction) => set({ action });
  const headerTypes = a.type === "buttons" ? ["none", "text", "image", "video", "document"] : ["none", "text"];
  const headerAsset = content.header.asset_id ? (assets[content.header.asset_id] ?? null) : null;

  function switchAction(type: InteractiveAction["type"]) {
    if (type === a.type) return;
    const next: InteractiveAction =
      type === "buttons" ? { type, buttons: [{ title: "" }] } : type === "cta_url" ? { type, display_text: "", url: "https://" } : { type, button: "View options", sections: [{ title: "", rows: [{ title: "" }] }] };
    // Media headers only work with reply buttons.
    const header = type !== "buttons" && !["none", "text"].includes(content.header.type) ? { type: "none" as const } : content.header;
    onChange({ ...content, action: next, header });
  }

  return (
    <div className="space-y-5">
      <fieldset>
        <legend className="mb-2 text-[13px] font-medium">Type</legend>
        <div className="grid gap-2 sm:grid-cols-3">
          {ACTIONS.map((o) => (
            <label key={o.type} className={clsx("cursor-pointer rounded-lg border p-3 has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-mint", a.type === o.type ? "border-teal bg-teal-soft/50" : "border-line hover:border-teal/40")}>
              <input type="radio" name={`${idPrefix}-action`} className="sr-only" checked={a.type === o.type} onChange={() => switchAction(o.type)} />
              <span className="block text-sm font-medium">{o.label}</span>
              <span className="mt-0.5 block text-xs text-muted">{o.hint}</span>
            </label>
          ))}
        </div>
      </fieldset>

      <div className="grid gap-3 sm:grid-cols-[160px_1fr]">
        <Field label="Header" htmlFor={`${idPrefix}-ht`} error={errors["header.type"]}>
          <Select id={`${idPrefix}-ht`} value={content.header.type} onChange={(e) => set({ header: { type: e.target.value as InteractiveContent["header"]["type"] } })}>
            {headerTypes.map((t) => (
              <option key={t} value={t}>
                {t === "none" ? "None" : t[0].toUpperCase() + t.slice(1)}
              </option>
            ))}
          </Select>
        </Field>
        {content.header.type === "text" && (
          <Field label="Header text" htmlFor={`${idPrefix}-htext`} error={errors["header.text"]}>
            <Input id={`${idPrefix}-htext`} value={content.header.text ?? ""} onChange={(e) => set({ header: { ...content.header, text: e.target.value } })} maxLength={60} invalid={!!errors["header.text"]} />
          </Field>
        )}
      </div>
      {["image", "video", "document"].includes(content.header.type) && (
        <AssetUpload
          key={content.header.type}
          kind={content.header.type as MediaType}
          asset={headerAsset}
          error={errors["header.asset_id"]}
          onChange={(x) => {
            if (x) onAsset(x);
            set({ header: { ...content.header, asset_id: x?.id ?? null } });
          }}
        />
      )}

      <BodyField id={`${idPrefix}-body`} label="Message text" value={content.body} onChange={(body) => set({ body })} max={a.type === "list" ? 4096 : 1024} error={errors.body} customFields={customFields} />
      <Field label="Footer (optional)" htmlFor={`${idPrefix}-foot`} error={errors.footer}>
        <Input id={`${idPrefix}-foot`} value={content.footer ?? ""} onChange={(e) => set({ footer: e.target.value })} maxLength={60} invalid={!!errors.footer} />
      </Field>

      {a.type === "buttons" && (
        <fieldset className="space-y-2">
          <legend className="mb-1 text-[13px] font-medium">Buttons</legend>
          {errors["action.buttons"] && <p className="text-[13px] text-brick">{errors["action.buttons"]}</p>}
          {a.buttons.map((b, i) => (
            <div key={i} className="flex items-start gap-2">
              <div className="flex-1">
                <Input
                  aria-label={`Button ${i + 1} label`}
                  placeholder={`Button ${i + 1} label`}
                  value={b.title}
                  maxLength={20}
                  invalid={!!errors[`action.buttons.${i}.title`]}
                  onChange={(e) => setAction({ ...a, buttons: a.buttons.map((x, j) => (j === i ? { ...x, title: e.target.value } : x)) })}
                />
                {errors[`action.buttons.${i}.title`] && <p className="mt-1 text-[13px] text-brick">{errors[`action.buttons.${i}.title`]}</p>}
              </div>
              <span className="mt-2.5">
                <Counter value={b.title} max={20} />
              </span>
              <button type="button" disabled={a.buttons.length === 1} onClick={() => setAction({ ...a, buttons: a.buttons.filter((_, j) => j !== i) })} className="mt-1.5 rounded p-1.5 text-muted hover:bg-paper hover:text-brick disabled:opacity-30" aria-label={`Remove button ${i + 1}`}>
                <Trash2 className="size-4" />
              </button>
            </div>
          ))}
          {a.buttons.length < 3 && (
            <button type="button" onClick={() => setAction({ ...a, buttons: [...a.buttons, { title: "" }] })} className="inline-flex items-center gap-1 text-[13px] font-medium text-teal hover:underline">
              <Plus className="size-4" /> Add button
            </button>
          )}
        </fieldset>
      )}

      {a.type === "cta_url" && (
        <div className="grid gap-3 sm:grid-cols-[200px_1fr]">
          <Field label="Button text" htmlFor={`${idPrefix}-cta`} error={errors["action.display_text"]}>
            <Input id={`${idPrefix}-cta`} value={a.display_text} maxLength={20} onChange={(e) => setAction({ ...a, display_text: e.target.value })} invalid={!!errors["action.display_text"]} />
          </Field>
          <Field label="Link" htmlFor={`${idPrefix}-url`} error={errors["action.url"]}>
            <Input id={`${idPrefix}-url`} type="url" value={a.url} onChange={(e) => setAction({ ...a, url: e.target.value })} invalid={!!errors["action.url"]} />
          </Field>
        </div>
      )}

      {a.type === "list" && (
        <div className="space-y-4">
          <Field label="Menu button text" htmlFor={`${idPrefix}-lb`} error={errors["action.button"]}>
            <Input id={`${idPrefix}-lb`} value={a.button} maxLength={20} onChange={(e) => setAction({ ...a, button: e.target.value })} invalid={!!errors["action.button"]} />
          </Field>
          {errors["action.sections"] && <p className="text-[13px] text-brick">{errors["action.sections"]}</p>}
          {a.sections.map((s, si) => (
            <fieldset key={si} className="space-y-2 rounded-lg border border-line p-3">
              <legend className="px-1 text-[13px] font-medium">Section {si + 1}</legend>
              <div className="flex gap-2">
                <Input
                  aria-label={`Section ${si + 1} title`}
                  placeholder={a.sections.length > 1 ? "Section title" : "Section title (optional)"}
                  value={s.title ?? ""}
                  maxLength={24}
                  invalid={!!errors[`action.sections.${si}.title`]}
                  onChange={(e) => setAction({ ...a, sections: a.sections.map((x, j) => (j === si ? { ...x, title: e.target.value } : x)) })}
                />
                {a.sections.length > 1 && (
                  <button type="button" onClick={() => setAction({ ...a, sections: a.sections.filter((_, j) => j !== si) })} className="rounded p-1.5 text-muted hover:bg-paper hover:text-brick" aria-label={`Remove section ${si + 1}`}>
                    <Trash2 className="size-4" />
                  </button>
                )}
              </div>
              {errors[`action.sections.${si}.title`] && <p className="text-[13px] text-brick">{errors[`action.sections.${si}.title`]}</p>}
              {s.rows.map((r, ri) => {
                const base = `action.sections.${si}.rows.${ri}`;
                const setRow = (patch: Partial<typeof r>) => setAction({ ...a, sections: a.sections.map((x, j) => (j === si ? { ...x, rows: x.rows.map((y, k) => (k === ri ? { ...y, ...patch } : y)) } : x)) });
                return (
                  <div key={ri} className="grid gap-2 pl-3 sm:grid-cols-[1fr_1fr_auto]">
                    <div>
                      <Input aria-label={`Option ${ri + 1} title`} placeholder="Option title" value={r.title} maxLength={24} onChange={(e) => setRow({ title: e.target.value })} invalid={!!errors[`${base}.title`]} />
                      {errors[`${base}.title`] && <p className="mt-1 text-[13px] text-brick">{errors[`${base}.title`]}</p>}
                    </div>
                    <Input aria-label={`Option ${ri + 1} description`} placeholder="Description (optional)" value={r.description ?? ""} maxLength={72} onChange={(e) => setRow({ description: e.target.value })} />
                    <button
                      type="button"
                      disabled={s.rows.length === 1}
                      onClick={() => setAction({ ...a, sections: a.sections.map((x, j) => (j === si ? { ...x, rows: x.rows.filter((_, k) => k !== ri) } : x)) })}
                      className="rounded p-1.5 text-muted hover:bg-paper hover:text-brick disabled:opacity-30"
                      aria-label={`Remove option ${ri + 1}`}
                    >
                      <Trash2 className="size-4" />
                    </button>
                  </div>
                );
              })}
              {a.sections.flatMap((x) => x.rows).length < 10 && (
                <button type="button" onClick={() => setAction({ ...a, sections: a.sections.map((x, j) => (j === si ? { ...x, rows: [...x.rows, { title: "" }] } : x)) })} className="ml-3 inline-flex items-center gap-1 text-[13px] font-medium text-teal hover:underline">
                  <Plus className="size-4" /> Add option
                </button>
              )}
            </fieldset>
          ))}
          {a.sections.length < 10 && a.sections.flatMap((x) => x.rows).length < 10 && (
            <button type="button" onClick={() => setAction({ ...a, sections: [...a.sections, { title: "", rows: [{ title: "" }] }] })} className="inline-flex items-center gap-1 text-[13px] font-medium text-teal hover:underline">
              <Plus className="size-4" /> Add section
            </button>
          )}
        </div>
      )}
    </div>
  );
}

export function ContentEditor(props: {
  type: ReplyType;
  content: AnyContent;
  onChange: (c: AnyContent) => void;
  errors: Errors;
  customFields: CustomField[];
  assets: Record<number, BotAsset>;
  onAsset: (a: BotAsset) => void;
  idPrefix?: string;
}) {
  if (props.type === "text") return <TextEditor {...props} content={props.content as TextContent} onChange={props.onChange} />;
  if (props.type === "media") return <MediaEditor {...props} content={props.content as MediaContent} onChange={props.onChange} />;
  return <InteractiveEditor {...props} content={props.content as InteractiveContent} onChange={props.onChange} />;
}
