import { Bookmark, Clock3, Eye, MessageCircle, Send, Share2, Star } from "lucide-react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useMemo, useState } from "react";
import { Link, useParams } from "react-router-dom";
import { useSession } from "../app/store/session";
import { commentsApi, contentApi } from "../shared/api/endpoints";
import { normalizeContentItem, normalizeContentList, toEntity, toList } from "../shared/api/normalize";
import { queryKeys } from "../shared/api/queryKeys";
import { Badge } from "../shared/ui/Badge";
import { Button } from "../shared/ui/Button";
import { Textarea } from "../shared/ui/Field";
import { MaterialCard } from "../shared/ui/MaterialCard";
import { ResponsiveImage } from "../shared/ui/ResponsiveImage";
import { EmptyState, ErrorState, Skeleton } from "../shared/ui/States";
import { NotFoundPage } from "./NotFoundPage";

function normalizeComment(comment) {
  return {
    id: comment.id ?? `${comment.createdAt ?? Date.now()}-${comment.author?.id ?? comment.user?.id ?? "comment"}`,
    author: comment.author?.name ?? comment.author ?? comment.user?.name ?? "Гость",
    text: comment.text ?? comment.content ?? comment.body ?? "",
    createdAt: comment.createdAt ?? comment.date ?? "",
  };
}

function formatDate(value) {
  if (!value) return "";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return value;
  return date.toLocaleString("ru-RU", { day: "numeric", month: "long", year: "numeric" });
}

function RatingBlock({ material, detailKey }) {
  const queryClient = useQueryClient();
  const initialAverage = Number(material.ratingAverage ?? material.rating ?? 0);
  const initialCount = Number(material.ratingCount ?? material.ratingsCount ?? 0);
  const currentRating = Number(material.myRating ?? 0);
  const [selectedRating, setSelectedRating] = useState(currentRating);

  const rateMutation = useMutation({
    mutationFn: (rating) => contentApi.update(material.id, { rating }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: queryKeys.contentDetail(detailKey) });
      queryClient.invalidateQueries({ queryKey: queryKeys.contentDetail(material.id) });
    },
  });

  const average = initialAverage.toFixed(1);

  return (
    <section className="rounded-lg border border-line bg-surface p-5">
      <div className="flex items-center justify-between gap-4">
        <div>
          <h2 className="font-serif text-xl">Оцените материал</h2>
          <p className="mt-1 text-sm text-muted">Средняя оценка: {average} из 5, оценок: {initialCount}</p>
        </div>
        <span className="font-serif text-3xl text-primary">{average}</span>
      </div>
      <div className="mt-4 flex gap-1" role="radiogroup" aria-label="Оценка материала">
        {[1, 2, 3, 4, 5].map((value) => (
          <button
            key={value}
            type="button"
            className="rounded-md p-1 text-warning transition hover:bg-warning-soft focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent"
            onClick={() => {
              setSelectedRating(value);
              rateMutation.mutate(value);
            }}
            aria-label={`Поставить ${value}`}
            aria-checked={selectedRating === value}
            role="radio"
          >
            <Star
              className="size-6"
              fill={value <= (selectedRating || Math.round(initialAverage)) ? "currentColor" : "none"}
            />
          </button>
        ))}
      </div>
      {rateMutation.isPending && <p className="mt-3 text-sm font-semibold text-muted">Сохраняем оценку...</p>}
      {rateMutation.isSuccess && <p className="mt-3 text-sm font-semibold text-success">Спасибо, ваша оценка учтена.</p>}
      {rateMutation.isError && <p className="mt-3 text-sm font-semibold text-danger">Не удалось сохранить оценку.</p>}
    </section>
  );
}

function CommentsBlock({ materialId }) {
  const user = useSession((state) => state.user);
  const [commentText, setCommentText] = useState("");
  const [notice, setNotice] = useState("");
  const queryClient = useQueryClient();

  const commentsQuery = useQuery({
    queryKey: queryKeys.comments(materialId),
    queryFn: () => commentsApi.list(materialId),
    enabled: Boolean(materialId),
  });

  const createComment = useMutation({
    mutationFn: (text) => commentsApi.create(materialId, { text }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: queryKeys.comments(materialId) });
      setCommentText("");
      setNotice("Комментарий добавлен.");
    },
  });

  const comments = useMemo(() => toList(commentsQuery.data).map(normalizeComment), [commentsQuery.data]);

  const submitComment = (event) => {
    event.preventDefault();
    const text = commentText.trim();
    if (!text) return;

    setNotice("");
    createComment.mutate(text);
  };

  return (
    <section className="page-shell border-t border-line py-14">
      <div className="flex items-center gap-3">
        <MessageCircle className="size-6 text-primary" />
        <h2 className="font-serif text-3xl">Комментарии</h2>
        <Badge>{comments.length}</Badge>
      </div>

      <form className="mt-6 rounded-lg border border-line bg-surface p-5" onSubmit={submitComment}>
        <Textarea
          label={user ? "Ваш комментарий" : "Комментарий гостя"}
          value={commentText}
          onChange={(event) => setCommentText(event.target.value)}
          placeholder="Напишите, что думаете о материале..."
        />
        <div className="mt-4 flex items-center gap-4">
          <Button type="submit" loading={createComment.isPending} icon={<Send className="size-4" />}>
            Отправить
          </Button>
          {notice && <span className="text-sm font-semibold text-success">{notice}</span>}
          {createComment.isError && <span className="text-sm font-semibold text-danger">Не удалось отправить комментарий.</span>}
        </div>
      </form>

      <div className="mt-7 grid gap-4">
        {commentsQuery.isLoading ? (
          [1, 2].map((item) => <Skeleton key={item} className="h-28 w-full" />)
        ) : commentsQuery.isError ? (
          <ErrorState retry={commentsQuery.refetch} />
        ) : comments.length ? (
          comments.map((comment) => (
            <article key={comment.id} className="rounded-lg border border-line bg-surface p-5">
              <div className="flex items-baseline justify-between gap-4">
                <h3 className="font-semibold text-ink">{comment.author}</h3>
                <span className="text-xs text-muted">{formatDate(comment.createdAt)}</span>
              </div>
              <p className="mt-3 leading-7 text-muted">{comment.text}</p>
            </article>
          ))
        ) : (
          <EmptyState title="Комментариев пока нет" text="Оставленные через API комментарии появятся в этом блоке." />
        )}
      </div>
    </section>
  );
}

export function MaterialPage() {
  const { slug } = useParams();
  const contentQuery = useQuery({
    queryKey: queryKeys.contentDetail(slug),
    queryFn: () => contentApi.get(slug),
    enabled: Boolean(slug),
  });
  const material = normalizeContentItem(toEntity(contentQuery.data));
  const materialId = material?.id ?? material?.slug;
  const relatedQuery = useQuery({
    queryKey: queryKeys.content({ relatedTo: materialId }),
    queryFn: () => contentApi.list({ limit: 3, exclude: materialId }),
    enabled: Boolean(materialId),
  });
  const relatedMaterials = normalizeContentList(relatedQuery.data).filter((item) => item.id !== materialId);

  if (contentQuery.isLoading) {
    return (
      <div className="page-shell grid gap-6 py-10">
        <Skeleton className="h-80 w-full" />
        <Skeleton className="h-96 w-full" />
      </div>
    );
  }

  if (contentQuery.isError) {
    return (
      <div className="page-shell py-16">
        <ErrorState retry={contentQuery.refetch} />
      </div>
    );
  }

  if (!material?.id) return <NotFoundPage />;

  const paragraphs = String(material.content ?? material.body ?? "").split(/\n{2,}/).filter(Boolean);

  return (
    <article>
      <header className="border-b border-line">
        <div className="mx-auto max-w-5xl px-4 py-10 sm:px-6 sm:py-16">
          <div className="flex flex-wrap items-center gap-3 text-sm">
            <Link className="text-muted hover:text-primary" to="/materials">
              Материалы
            </Link>
            <span className="text-line">/</span>
            <Badge tone="accent">{material.category}</Badge>
          </div>
          <h1 className="mt-6 max-w-4xl font-serif text-4xl leading-[1.08] tracking-[-0.025em] sm:text-6xl">
            {material.title}
          </h1>
          <p className="mt-6 max-w-3xl text-lg leading-8 text-muted">{material.excerpt}</p>
          <div className="mt-8 flex flex-wrap items-center gap-x-6 gap-y-3 border-t border-line pt-6 text-sm text-muted">
            <span className="font-semibold text-ink">{material.author}</span>
            <span>{formatDate(material.publishedAt)}</span>
            <span className="flex items-center gap-1.5">
              <Clock3 className="size-4" /> {material.readingTime} мин
            </span>
            <span className="flex items-center gap-1.5">
              <Eye className="size-4" /> {Number(material.views ?? 0).toLocaleString("ru-RU")}
            </span>
          </div>
        </div>
      </header>

      <div className="page-shell py-8">
        <ResponsiveImage src={material.image} alt="" eager className="aspect-[16/8] w-full rounded-xl object-cover" />
      </div>

      <div className="page-shell grid gap-10 py-8 lg:grid-cols-[minmax(0,4fr)_minmax(14rem,1fr)]">
        <div className="max-w-[68ch]">
          {paragraphs.map((paragraph) => (
            <p key={paragraph} className="mb-6 font-serif text-xl leading-9 text-ink/90">
              {paragraph}
            </p>
          ))}
          <div className="mt-10 flex flex-wrap gap-2 border-t border-line pt-6">
            {(material.tags ?? []).map((tag) => (
              <Badge key={tag}>#{tag}</Badge>
            ))}
          </div>
        </div>
        <aside className="order-first lg:order-last">
          <div className="grid gap-3 lg:sticky lg:top-24">
            <RatingBlock material={material} detailKey={slug} />
            <div className="grid gap-2 rounded-lg border border-line bg-surface p-3">
              <Button variant="secondary" icon={<Bookmark className="size-4" />}>Сохранить</Button>
              <Button variant="ghost" icon={<Share2 className="size-4" />}>Поделиться</Button>
            </div>
          </div>
        </aside>
      </div>

      <CommentsBlock materialId={materialId} />

      <section className="page-shell border-t border-line py-14">
        <h2 className="font-serif text-3xl">Читайте также</h2>
        <div className="mt-7 grid gap-6 md:grid-cols-3">
          {relatedQuery.isLoading && [1, 2, 3].map((item) => <Skeleton key={item} className="h-72" />)}
          {relatedQuery.isError && (
            <div className="md:col-span-3">
              <ErrorState retry={relatedQuery.refetch} />
            </div>
          )}
          {relatedQuery.isSuccess && relatedMaterials.length > 0 && relatedMaterials.slice(0, 3).map((item) => (
            <MaterialCard key={item.id} material={item} compact />
          ))}
          {relatedQuery.isSuccess && relatedMaterials.length === 0 && (
            <div className="md:col-span-3">
              <EmptyState title="Похожих материалов нет" text="Backend пока не вернул дополнительные записи." />
            </div>
          )}
        </div>
      </section>
    </article>
  );
}
