"use client";

import type { CommentEntityType } from "@capakraken/shared";
import { useState } from "react";
import { clsx } from "clsx";
import { trpc } from "~/lib/trpc/client.js";
import { ConfirmDialog } from "~/components/ui/ConfirmDialog.js";
import { CommentInput } from "./CommentInput.js";
import { sanitizeHtml } from "~/lib/sanitize.js";

interface CommentTarget {
  entityType: CommentEntityType;
  entityId: string;
}

interface CommentAuthor {
  id: string;
  name: string | null;
  email: string;
  image: string | null;
}

interface CommentReply {
  id: string;
  body: string;
  resolved: boolean;
  createdAt: Date | string;
  author: CommentAuthor;
}

interface CommentItem {
  id: string;
  body: string;
  resolved: boolean;
  createdAt: Date | string;
  author: CommentAuthor;
  replies: CommentReply[];
}

interface CommentThreadProps {
  commentTarget: CommentTarget;
}

function formatRelativeTime(date: Date | string): string {
  const d = date instanceof Date ? date : new Date(date);
  const now = new Date();
  const diffMs = now.getTime() - d.getTime();
  const diffMinutes = Math.floor(diffMs / 60_000);

  if (diffMinutes < 1) return "just now";
  if (diffMinutes < 60) return `${diffMinutes}m ago`;
  const diffHours = Math.floor(diffMinutes / 60);
  if (diffHours < 24) return `${diffHours}h ago`;
  const diffDays = Math.floor(diffHours / 24);
  if (diffDays < 7) return `${diffDays}d ago`;
  return d.toLocaleDateString();
}

function AuthorAvatar({ author }: { author: CommentAuthor }) {
  const initials = author.name
    ? author.name
        .split(" ")
        .map((n) => n[0])
        .join("")
        .slice(0, 2)
        .toUpperCase()
    : author.email.charAt(0).toUpperCase();

  return (
    <span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-brand-100 dark:bg-sky-800 text-xs font-semibold text-brand-700 dark:text-sky-200">
      {initials}
    </span>
  );
}

/**
 * Render comment body with @mention highlights.
 * Transforms @[Name](userId) into styled spans.
 */
function CommentBody({ body }: { body: string }) {
  const cleanBody = sanitizeHtml(body);
  const parts: Array<{ type: "text" | "mention"; value: string }> = [];
  const regex = /@\[([^\]]+)\]\([^)]+\)/g;
  let lastIndex = 0;
  let match: RegExpExecArray | null;

  while ((match = regex.exec(cleanBody)) !== null) {
    if (match.index > lastIndex) {
      parts.push({ type: "text", value: cleanBody.slice(lastIndex, match.index) });
    }
    parts.push({ type: "mention", value: `@${match[1]}` });
    lastIndex = match.index + match[0].length;
  }

  if (lastIndex < cleanBody.length) {
    parts.push({ type: "text", value: cleanBody.slice(lastIndex) });
  }

  return (
    <p className="text-sm text-gray-800 dark:text-gray-200 whitespace-pre-wrap break-words">
      {parts.map((part, i) =>
        part.type === "mention" ? (
          <span
            key={i}
            className="rounded bg-brand-50 dark:bg-sky-900/50 px-1 py-0.5 text-brand-700 dark:text-sky-300 font-medium text-xs"
          >
            {part.value}
          </span>
        ) : (
          <span key={i}>{part.value}</span>
        ),
      )}
    </p>
  );
}

function SingleComment({
  comment,
  commentTarget,
  isReply = false,
}: {
  comment: CommentItem | CommentReply;
  commentTarget: CommentTarget;
  isReply?: boolean;
}) {
  const [showReplyInput, setShowReplyInput] = useState(false);
  const [confirmDelete, setConfirmDelete] = useState(false);
  const utils = trpc.useUtils();
  const createMutation = trpc.comment.create.useMutation({
    onSuccess: () => {
      setShowReplyInput(false);
      void utils.comment.list.invalidate(commentTarget);
      void utils.comment.count.invalidate(commentTarget);
    },
  });

  const resolveMutation = trpc.comment.resolve.useMutation({
    onSuccess: () => {
      void utils.comment.list.invalidate(commentTarget);
    },
  });

  const deleteMutation = trpc.comment.delete.useMutation({
    onSuccess: () => {
      void utils.comment.list.invalidate(commentTarget);
      void utils.comment.count.invalidate(commentTarget);
    },
  });

  const isResolved = comment.resolved;

  return (
    <div
      className={clsx(
        "group relative",
        isResolved && "opacity-60",
      )}
    >
      <div className={clsx("flex gap-3", isReply && "ml-10")}>
        <AuthorAvatar author={comment.author} />
        <div className="min-w-0 flex-1">
          <div className="flex items-center gap-2">
            <span className="text-sm font-semibold text-gray-900 dark:text-gray-100">
              {comment.author.name ?? comment.author.email}
            </span>
            <span className="text-xs text-gray-400">
              {formatRelativeTime(comment.createdAt)}
            </span>
            {isResolved && (
              <span className="rounded-full bg-emerald-100 dark:bg-emerald-900/50 px-2 py-0.5 text-xs font-medium text-emerald-700 dark:text-emerald-300">
                Resolved
              </span>
            )}
          </div>

          <div className={clsx(isResolved && "line-through decoration-gray-300 dark:decoration-gray-600")}>
            <CommentBody body={comment.body} />
          </div>

          {/* Action buttons */}
          <div className="mt-1 flex items-center gap-3 opacity-0 group-hover:opacity-100 transition-opacity">
            {!isReply && (
              <button
                type="button"
                onClick={() => setShowReplyInput((prev) => !prev)}
                className="text-xs text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
              >
                Reply
              </button>
            )}
            {!isReply && (
              <button
                type="button"
                onClick={() =>
                  resolveMutation.mutate({
                    id: comment.id,
                    resolved: !isResolved,
                  })
                }
                disabled={resolveMutation.isPending}
                className="text-xs text-gray-400 hover:text-emerald-600 dark:hover:text-emerald-400"
              >
                {isResolved ? "Unresolve" : "Resolve"}
              </button>
            )}
            <button
              type="button"
              onClick={() => setConfirmDelete(true)}
              disabled={deleteMutation.isPending}
              className="text-xs text-gray-400 hover:text-rose-600 dark:hover:text-rose-400"
            >
              Delete
            </button>
          </div>

          {/* Inline reply input */}
          {showReplyInput && (
            <div className="mt-3">
                <CommentInput
                  entityType={commentTarget.entityType}
                  entityId={commentTarget.entityId}
                  parentId={comment.id}
                  onSubmit={(replyBody) => {
                    createMutation.mutate({
                      entityType: commentTarget.entityType,
                      entityId: commentTarget.entityId,
                      parentId: comment.id,
                      body: replyBody,
                    });
                }}
                onCancel={() => setShowReplyInput(false)}
                isSubmitting={createMutation.isPending}
                placeholder="Write a reply..."
                autoFocus
              />
            </div>
          )}
        </div>
      </div>

      {confirmDelete && (
        <ConfirmDialog
          title="Delete comment"
          message="Are you sure you want to delete this comment?"
          confirmLabel="Delete"
          variant="danger"
          onConfirm={() => {
            deleteMutation.mutate({ id: comment.id });
            setConfirmDelete(false);
          }}
          onCancel={() => setConfirmDelete(false)}
        />
      )}

      {/* Render replies */}
      {"replies" in comment && comment.replies.length > 0 && (
        <div className="mt-3 space-y-3 border-l-2 border-gray-100 dark:border-gray-700 pl-2">
          {comment.replies.map((reply) => (
            <SingleComment
              key={reply.id}
              comment={reply}
              commentTarget={commentTarget}
              isReply
            />
          ))}
        </div>
      )}
    </div>
  );
}

export function CommentThread({ commentTarget }: CommentThreadProps) {
  const utils = trpc.useUtils();

  const commentsQuery = trpc.comment.list.useQuery(
    commentTarget,
    { staleTime: 10_000 },
  );

  const createMutation = trpc.comment.create.useMutation({
    onSuccess: () => {
      void utils.comment.list.invalidate(commentTarget);
      void utils.comment.count.invalidate(commentTarget);
    },
  });

  const comments = (commentsQuery.data ?? []) as CommentItem[];

  return (
    <div className="space-y-6">
      {/* Comment list */}
      {commentsQuery.isLoading ? (
        <div className="space-y-4">
          {[1, 2].map((i) => (
            <div key={i} className="flex gap-3">
              <div className="h-8 w-8 shimmer-skeleton rounded-full" />
              <div className="flex-1 space-y-2">
                <div className="h-4 w-32 shimmer-skeleton rounded" />
                <div className="h-12 shimmer-skeleton rounded-lg" />
              </div>
            </div>
          ))}
        </div>
      ) : comments.length === 0 ? (
        <p className="text-center text-sm text-gray-400 py-6">
          No comments yet. Start the conversation below.
        </p>
      ) : (
        <div className="space-y-5">
          {comments.map((comment) => (
            <SingleComment
              key={comment.id}
              comment={comment}
              commentTarget={commentTarget}
            />
          ))}
        </div>
      )}

      {/* New comment input */}
      <div className="border-t border-gray-200 dark:border-gray-700 pt-4">
        <CommentInput
          entityType={commentTarget.entityType}
          entityId={commentTarget.entityId}
          onSubmit={(body) => {
            createMutation.mutate({
              entityType: commentTarget.entityType,
              entityId: commentTarget.entityId,
              body,
            });
          }}
          isSubmitting={createMutation.isPending}
        />
      </div>
    </div>
  );
}
