"use client";

import { useState } from "react";
import Image from "next/image";
import Link from "next/link";
import { useAppSelector } from "@/redux/hooks";
import {
  useCreateCommentMutation,
  useLazyGetCommentsQuery,
} from "@/api/blog.api";
import type { IBlogCommentsBlock } from "@/api/types/blog";
import {
  AVATAR_FALLBACK,
  mapBlogComment,
  type MappedBlogComment,
} from "@/utils/mapBlogComment";

import Avatar from "@/components/common/Avatar";

const FALLBACK_PATH = AVATAR_FALLBACK;

interface Comment {
  id: number;
  authorUserId: number;
  author: string;
  rank?: string;
  avatar: string;
  date: string;
  content: string;
  likes: number;
  replies?: Comment[];
  repliesCount?: number;
  parentId?: number;
}

interface CommentsBlogProps {
  postId: number;
  postCode: string;
  postAuthorId?: number;
  commentsCount: number;
  comments: Comment[];
  canPost?: boolean;
  onSubscribeClick?: () => void;
}

// ── Reply form ────────────────────────────────────────────────────────────────

const ReplyForm: React.FC<{
  postId: number;
  postCode: string;
  parentId: number;
  onCancel: () => void;
  onSuccess: () => Promise<void>;
}> = ({ postId, postCode, parentId, onCancel, onSuccess }) => {
  const [text, setText] = useState("");
  const isAuthenticated = useAppSelector((s) => s.auth.isAuthenticated);
  const [createComment, { isLoading }] = useCreateCommentMutation();

  const handleSubmit = async () => {
    const trimmed = text.trim();
    if (!trimmed || isLoading || !isAuthenticated) return;
    try {
      await createComment({
        postId,
        postCode,
        content: trimmed,
        parentId,
      }).unwrap();
      setText("");
      await onSuccess();
    } catch (err) {
      console.error("Failed to post reply", err);
    }
  };

  return (
    <div className="mt-2.5">
      <textarea
        value={text}
        onChange={(e) => setText(e.target.value)}
        rows={3}
        placeholder="Write a reply..."
        className="w-full resize-none outline-none font-sans text-sm text-black bg-[#FAFAFA] rounded-xl px-4 py-3 border-[1.5px] border-[#e5e7eb] focus:border-[#3b82f6] transition-colors"
      />
      <div className="flex items-center gap-2 mt-2">
        <button
          onClick={handleSubmit}
          disabled={isLoading || !text.trim()}
          className="px-4 py-1.5 text-[12px] font-medium bg-white border border-[#393939] text-[#393939] rounded-full cursor-pointer hover:bg-[#f9fafb] transition-colors disabled:opacity-40 disabled:cursor-not-allowed font-sans"
        >
          {isLoading ? "Posting..." : "Post Reply"}
        </button>
        <button
          onClick={onCancel}
          className="px-4 py-2 text-[12px] font-medium text-[#9ca3af] bg-transparent border-none cursor-pointer hover:text-[#6b7280] transition-colors font-sans"
        >
          Cancel
        </button>
      </div>
    </div>
  );
};

// ── Comment item ──────────────────────────────────────────────────────────────

// On first render a comment shows at most this many embedded replies; the rest
// are loaded on demand, one page at a time, via the comment list API.
const REPLIES_PREVIEW_COUNT = 5;
const REPLIES_PER_PAGE = 20;

const CommentItem: React.FC<{
  comment: Comment;
  postId: number;
  postCode: string;
  postAuthorId?: number;
  isReply?: boolean;
  canPost: boolean;
  onSubscribeClick?: () => void;
  onRefresh: () => Promise<void>;
}> = ({
  comment,
  postId,
  postCode,
  postAuthorId,
  isReply = false,
  canPost,
  onSubscribeClick,
  onRefresh,
}) => {
  const [isReplying, setIsReplying] = useState(false);
  const isAuthenticated = useAppSelector((s) => s.auth.isAuthenticated);
  const currentUserId = useAppSelector((s) => s.auth.user?.id);

  // Link the commenter's avatar/name to their public profile, unless the
  // comment is the current user's own (no point linking to yourself).
  const isSelf =
    currentUserId != null &&
    String(comment.authorUserId) === String(currentUserId);
  const profileHref = `/user-profile?userId=${comment.authorUserId}`;

  // Reply pagination (only meaningful for top-level comments).
  const [fetchReplies, { isFetching: isFetchingReplies }] =
    useLazyGetCommentsQuery();
  const [loadedReplies, setLoadedReplies] = useState<MappedBlogComment[]>([]);
  const [repliesPage, setRepliesPage] = useState(0);
  const [repliesTotalPages, setRepliesTotalPages] = useState(0);
  const [repliesExpanded, setRepliesExpanded] = useState(false);

  const embeddedReplies = comment.replies ?? [];
  const repliesCount = comment.repliesCount ?? embeddedReplies.length;
  const displayedReplies = repliesExpanded
    ? loadedReplies
    : embeddedReplies.slice(0, REPLIES_PREVIEW_COUNT);
  const hasMoreReplies = repliesExpanded
    ? repliesPage < repliesTotalPages
    : repliesCount > displayedReplies.length;

  const loadReplies = async (reset = false) => {
    const nextPage = reset || !repliesExpanded ? 1 : repliesPage + 1;
    try {
      const result = await fetchReplies({
        postId,
        page: nextPage,
        perPage: REPLIES_PER_PAGE,
        parentId: comment.id,
        sortDirection: "asc",
      }).unwrap();
      const mapped = (result.data ?? []).map(mapBlogComment);
      setLoadedReplies((prev) =>
        nextPage === 1 ? mapped : [...prev, ...mapped],
      );
      setRepliesPage(result.page ?? nextPage);
      setRepliesTotalPages(result.totalPages ?? 0);
      setRepliesExpanded(true);
    } catch (err) {
      console.error("Failed to load replies", err);
    }
  };

  const replyLabel = !isAuthenticated
    ? "Login to Reply"
    : !canPost
      ? "Subscribe to Reply"
      : "Reply";

  return (
    <li>
      <div className="flex gap-3">
        {isSelf ? (
          <Avatar
            src={comment.avatar}
            name={comment.author}
            size={isReply ? "blog-sm" : "blog-md"}
          />
        ) : (
          <Link href={profileHref} className="flex-shrink-0 no-underline">
            <Avatar
              src={comment.avatar}
              name={comment.author}
              size={isReply ? "blog-sm" : "blog-md"}
            />
          </Link>
        )}
        <div className="flex-1 min-w-0">
          {/* Header */}
          <div className="flex items-center flex-wrap gap-2 mb-1">
            {isSelf ? (
              <span className="font-semibold text-sm text-[#111827]">
                {comment.author}
              </span>
            ) : (
              <Link
                href={profileHref}
                className="font-semibold text-sm text-[#111827] hover:text-[#08A1EE] transition-colors no-underline"
              >
                {comment.author}
              </Link>
            )}
            {postAuthorId && comment.authorUserId === postAuthorId ? (
              <span className="text-xs text-[#9ca3af]">Author</span>
            ) : comment.rank ? (
              <span className="text-xs text-[#9ca3af]">{comment.rank}</span>
            ) : null}
            <span className="text-xs font-semibold text-black/50">
              {comment.date}
            </span>
          </div>

          {/* Body */}
          <p
            className={`text-black leading-[1.55] font-normal whitespace-pre-line ${isReply ? "text-base" : "text-[17px]"}`}
          >
            {comment.content}
          </p>

          {/* Reply button */}
          <button
            onClick={() => {
              if (!isAuthenticated) return;
              if (!canPost) {
                onSubscribeClick?.();
                return;
              }
              setIsReplying((v) => !v);
            }}
            className="mt-2 text-xs font-semibold text-[#08A1EE] bg-transparent border-none p-0 cursor-pointer hover:opacity-80 transition-opacity font-sans"
          >
            {replyLabel}
          </button>

          {/* Reply form */}
          {isReplying && canPost && (
            <ReplyForm
              postId={postId}
              postCode={postCode}
              parentId={comment?.parentId ? comment.parentId : comment.id}
              onCancel={() => setIsReplying(false)}
              onSuccess={async () => {
                await onRefresh();
                if (repliesExpanded) await loadReplies(true);
                setIsReplying(false);
              }}
            />
          )}
        </div>
      </div>

      {/* Nested replies */}
      {!isReply && embeddedReplies.length > 0 && (
        <ul className="list-none mt-4 ml-15 flex flex-col gap-4 border-l-2 border-[#f3f4f6] pl-5">
          {displayedReplies.map((reply) => (
            <CommentItem
              key={reply.id}
              comment={reply}
              postId={postId}
              postCode={postCode}
              postAuthorId={postAuthorId}
              isReply
              canPost={canPost}
              onSubscribeClick={onSubscribeClick}
              onRefresh={onRefresh}
            />
          ))}

          {hasMoreReplies && (
            <li>
              <button
                onClick={() => loadReplies()}
                disabled={isFetchingReplies}
                className="text-xs font-semibold text-[#08A1EE] bg-transparent border-none p-0 cursor-pointer hover:opacity-80 transition-opacity font-sans disabled:opacity-40 disabled:cursor-not-allowed"
              >
                {isFetchingReplies ? "Loading..." : "View more replies"}
              </button>
            </li>
          )}
        </ul>
      )}
    </li>
  );
};

// ── CommentsBlog ──────────────────────────────────────────────────────────────

const PER_PAGE = 20;

const CommentsBlog: React.FC<CommentsBlogProps> = ({
  postId,
  postCode,
  postAuthorId,
  commentsCount,
  comments,
  canPost = true,
  onSubscribeClick,
}) => {
  const [text, setText] = useState("");
  const isAuthenticated = useAppSelector((s) => s.auth.isAuthenticated);
  const [createComment, { isLoading: isSubmitting }] =
    useCreateCommentMutation();
  const [fetchComments, { isFetching }] = useLazyGetCommentsQuery();

  const [loadedComments, setLoadedComments] = useState<MappedBlogComment[]>([]);
  const [currentPage, setCurrentPage] = useState(0);
  const [totalPages, setTotalPages] = useState(0);
  const [totalRecords, setTotalRecords] = useState(commentsCount);
  const [hasLoaded, setHasLoaded] = useState(false);

  const visibleComments = hasLoaded ? loadedComments : comments;
  const headerCount = hasLoaded ? totalRecords : commentsCount;
  const remaining = Math.max(totalRecords - loadedComments.length, 0);
  const showInitialButton =
    !hasLoaded &&
    commentsCount > 0 &&
    commentsCount >
      comments.length +
        comments.reduce((sum, c) => sum + (c.replies?.length ?? 0), 0);

  // console.log(
  //   showInitialButton,
  //   comments.length +
  //     comments.reduce((sum, c) => sum + (c.replies?.length ?? 0), 0),
  //   commentsCount,
  // );
  const showLoadMoreButton =
    hasLoaded && currentPage < totalPages && remaining > 0;

  const applyPage = (result: IBlogCommentsBlock) => {
    const mapped = (result.data ?? []).map(mapBlogComment);
    setLoadedComments((prev) =>
      result.page === 1 ? mapped : [...prev, ...mapped],
    );
    setCurrentPage(result.page ?? 1);
    setTotalPages(result.totalPages ?? 0);
    setTotalRecords(result.totalRecords ?? 0);
    setHasLoaded(true);
  };

  const refreshComments = async () => {
    const pageToRefresh = hasLoaded ? Math.max(currentPage, 1) : 1;
    const refreshed: MappedBlogComment[] = [];
    let lastPage = pageToRefresh,
      lastTotalPages = totalPages,
      lastTotalRecords = totalRecords;
    for (let page = 1; page <= pageToRefresh; page++) {
      const result = await fetchComments({
        postId,
        page,
        perPage: PER_PAGE,
      }).unwrap();
      refreshed.push(...(result.data ?? []).map(mapBlogComment));
      lastPage = result.page ?? page;
      lastTotalPages = result.totalPages ?? 0;
      lastTotalRecords = result.totalRecords ?? 0;
    }
    setLoadedComments(refreshed);
    setCurrentPage(lastPage);
    setTotalPages(lastTotalPages);
    setTotalRecords(lastTotalRecords);
    setHasLoaded(true);
  };

  const handleLoadPage = async (page: number) => {
    try {
      const result = await fetchComments({
        postId,
        page,
        perPage: PER_PAGE,
        sortDirection: "desc",
      }).unwrap();
      applyPage(result);
    } catch (err) {
      console.error("Failed to load comments", err);
    }
  };

  const handleSubmit = async () => {
    const trimmed = text.trim();
    if (!trimmed || isSubmitting || !isAuthenticated) return;
    try {
      await createComment({ postId, postCode, content: trimmed }).unwrap();
      setText("");
      await refreshComments();
    } catch (err) {
      console.error("Failed to post comment", err);
    }
  };

  const submitLabel = !isAuthenticated
    ? "Login To Post Comment"
    : !canPost
      ? "Subscribe To Comment"
      : isSubmitting
        ? "Posting..."
        : "Post Comment";

  return (
    <section
      id="comments"
      className="scroll-mt-24 font-sans mt-10 border-t border-[#f3f4f6] pt-8 max-w-180"
    >
      {/* Heading */}
      <h3 className="font-normal text-[#484848] text-2xl tracking-[-0.01em] leading-[87.5%] mb-9">
        Comments ({commentsCount})
      </h3>

      {/* Write a comment */}
      <div className="mb-8">
        <textarea
          value={text}
          onChange={(e) => setText(e.target.value)}
          placeholder="Write a comment..."
          rows={4}
          disabled={!isAuthenticated || !canPost}
          onClick={() => {
            if (!isAuthenticated) return;
            if (!canPost) onSubscribeClick?.();
          }}
          className="w-full h-[130px] resize-none outline-none font-sans text-[17px] text-black bg-[#FAFAFA] rounded-xl p-4 border-[1.5px] border-transparent focus:border-[#3b82f6] transition-colors disabled:cursor-not-allowed"
        />
        <div className="mt-3">
          <button
            onClick={
              !isAuthenticated
                ? undefined
                : !canPost
                  ? onSubscribeClick
                  : handleSubmit
            }
            disabled={
              isSubmitting || (isAuthenticated && canPost && !text.trim())
            }
            className="h-8.75 px-5 text-sm font-medium bg-white border border-[#393939] text-[#393939] rounded-full cursor-pointer hover:bg-[#f9fafb] transition-colors disabled:opacity-40 disabled:cursor-not-allowed font-sans"
          >
            {submitLabel}
          </button>
        </div>
      </div>

      {/* Comment list */}
      <ul className="list-none flex flex-col gap-7" id="comment-list">
        {visibleComments.map((comment) => (
          <CommentItem
            key={comment.id}
            comment={comment}
            postId={postId}
            postCode={postCode}
            postAuthorId={postAuthorId}
            canPost={canPost}
            onSubscribeClick={onSubscribeClick}
            onRefresh={refreshComments}
          />
        ))}
      </ul>

      {/* Load more */}
      {(showInitialButton || showLoadMoreButton) && (
        <button
          onClick={() => handleLoadPage(hasLoaded ? currentPage + 1 : 1)}
          disabled={isFetching}
          className="mt-7 px-5 py-2 text-sm font-medium bg-white border border-[#393939] text-[#393939] rounded-full cursor-pointer hover:bg-[#f9fafb] transition-colors disabled:opacity-40 disabled:cursor-not-allowed font-sans"
        >
          {isFetching
            ? "Loading..."
            : hasLoaded
              ? `Show ${remaining} more ${remaining === 1 ? "comment" : "comments"}`
              : "See all comments"}
        </button>
      )}
    </section>
  );
};

export default CommentsBlog;
