"use client";

import { useActionState, useId, useState } from "react";
import { Button, ErrorText, HelpText, Input, Label, Textarea } from "@/components/ui";
import { type FormState, firstFieldError, initialFormState } from "@/lib/forms";
import { formatDate, isoDate } from "@/lib/format";
import type { PublicComment } from "@/lib/services/comments";

type CommentAction = (prev: FormState, formData: FormData) => Promise<FormState>;

function countComments(list: PublicComment[]): number {
  return list.reduce((sum, c) => sum + 1 + countComments(c.replies), 0);
}

function CommentForm({
  postId,
  parentId,
  action,
  onCancel,
}: {
  postId: number;
  parentId: number | null;
  action: CommentAction;
  onCancel?: () => void;
}) {
  const [state, formAction] = useActionState(action, initialFormState);
  const ids = useId();
  const err = (field: string) => firstFieldError(state, field);

  if (state.status === "success") {
    return (
      <p
        role="status"
        className="rounded-md border border-success/40 bg-success/10 px-4 py-3 text-sm text-success"
      >
        Thanks! Your comment is awaiting moderation and will appear once approved.
      </p>
    );
  }

  return (
    <form action={formAction} className="space-y-4">
      {state.formError && (
        <p
          role="alert"
          className="rounded-md border border-danger/40 bg-danger/10 px-4 py-2.5 text-sm text-danger"
        >
          {state.formError}
        </p>
      )}
      <input type="hidden" name="postId" value={postId} />
      <input type="hidden" name="parentId" value={parentId ?? ""} />
      {/* Honeypot — hidden from people, tempting to bots. */}
      <div className="hidden" aria-hidden="true">
        <label htmlFor={`${ids}-website`}>Website</label>
        <input id={`${ids}-website`} name="website" type="text" tabIndex={-1} autoComplete="off" />
      </div>

      <div className="grid gap-4 sm:grid-cols-2">
        <div>
          <Label htmlFor={`${ids}-name`}>Name</Label>
          <Input
            id={`${ids}-name`}
            name="authorName"
            required
            maxLength={120}
            autoComplete="name"
            aria-invalid={err("authorName") ? true : undefined}
          />
          <ErrorText>{err("authorName")}</ErrorText>
        </div>
        <div>
          <Label htmlFor={`${ids}-email`}>Email</Label>
          <Input
            id={`${ids}-email`}
            name="authorEmail"
            type="email"
            required
            maxLength={254}
            autoComplete="email"
            aria-invalid={err("authorEmail") ? true : undefined}
          />
          <ErrorText>{err("authorEmail")}</ErrorText>
        </div>
      </div>
      <label className="flex cursor-pointer items-start gap-2 text-sm text-ink">
        <input type="checkbox" name="emailPublic" className="mt-0.5 size-4 accent-(--link)" />
        <span>
          Show my email publicly
          <span className="block text-xs text-ink-muted">
            Leave unchecked to keep your email visible to the site owner only.
          </span>
        </span>
      </label>
      <div>
        <Label htmlFor={`${ids}-body`}>Comment</Label>
        <Textarea
          id={`${ids}-body`}
          name="body"
          required
          rows={parentId === null ? 5 : 3}
          maxLength={5000}
          aria-invalid={err("body") ? true : undefined}
        />
        <ErrorText>{err("body")}</ErrorText>
      </div>
      <div className="flex items-center gap-3">
        <Button type="submit">{parentId === null ? "Post comment" : "Post reply"}</Button>
        {onCancel && (
          <Button type="button" variant="ghost" onClick={onCancel}>
            Cancel
          </Button>
        )}
        <HelpText>Comments are reviewed before they appear.</HelpText>
      </div>
    </form>
  );
}

function CommentItem({
  comment,
  postId,
  action,
  replyTo,
  setReplyTo,
  depth,
}: {
  comment: PublicComment;
  postId: number;
  action: CommentAction;
  replyTo: number | null;
  setReplyTo: (id: number | null) => void;
  depth: number;
}) {
  return (
    <li>
      <article className="rounded-lg border border-edge bg-surface p-4">
        <header className="flex flex-wrap items-baseline gap-x-2 text-sm">
          <span className="font-semibold text-ink-strong">{comment.authorName}</span>
          {comment.authorEmail && (
            <a
              href={`mailto:${comment.authorEmail}`}
              className="text-xs text-link hover:underline"
            >
              {comment.authorEmail}
            </a>
          )}
          <time dateTime={isoDate(comment.createdAt)} className="text-xs text-ink-muted">
            {formatDate(comment.createdAt)}
          </time>
        </header>
        <p className="mt-2 whitespace-pre-wrap text-sm leading-relaxed text-ink">
          {comment.body}
        </p>
        <footer className="mt-2">
          <button
            type="button"
            className="text-xs font-medium text-link hover:underline"
            onClick={() => setReplyTo(replyTo === comment.id ? null : comment.id)}
          >
            {replyTo === comment.id ? "Close reply form" : "Reply"}
          </button>
        </footer>
      </article>

      {replyTo === comment.id && (
        <div className="mt-3 border-l-2 border-edge-strong pl-4">
          <CommentForm
            postId={postId}
            parentId={comment.id}
            action={action}
            onCancel={() => setReplyTo(null)}
          />
        </div>
      )}

      {comment.replies.length > 0 && (
        // Cap the visual indent so deep threads stay readable on phones.
        <ul className={`mt-3 space-y-3 ${depth < 4 ? "border-l-2 border-edge pl-4 sm:pl-6" : ""}`}>
          {comment.replies.map((reply) => (
            <CommentItem
              key={reply.id}
              comment={reply}
              postId={postId}
              action={action}
              replyTo={replyTo}
              setReplyTo={setReplyTo}
              depth={depth + 1}
            />
          ))}
        </ul>
      )}
    </li>
  );
}

export function CommentsSection({
  postId,
  comments,
  action,
}: {
  postId: number;
  comments: PublicComment[];
  action: CommentAction;
}) {
  const [replyTo, setReplyTo] = useState<number | null>(null);
  const total = countComments(comments);
  const ids = useId();

  return (
    <section aria-labelledby={`${ids}-comments`} className="mx-auto mt-12 max-w-[46rem] border-t border-edge pt-8">
      <h2 id={`${ids}-comments`} className="text-xl font-bold tracking-tight text-ink-bright">
        {total === 0 ? "Comments" : total === 1 ? "1 comment" : `${total} comments`}
      </h2>

      {total === 0 ? (
        <p className="mt-4 text-sm text-ink-muted">No comments yet. Start the conversation!</p>
      ) : (
        <ul className="mt-6 space-y-4">
          {comments.map((comment) => (
            <CommentItem
              key={comment.id}
              comment={comment}
              postId={postId}
              action={action}
              replyTo={replyTo}
              setReplyTo={setReplyTo}
              depth={0}
            />
          ))}
        </ul>
      )}

      <div className="mt-10">
        <h3 className="mb-4 text-lg font-semibold text-ink-strong">Leave a comment</h3>
        <CommentForm postId={postId} parentId={null} action={action} />
      </div>
    </section>
  );
}
