"use client";

import { Fragment, type ReactNode, useEffect, useMemo, useState } from "react";

import type { OptimizedArticle } from "../lib/domain/types";

interface OptimizedPreviewProps {
  article: OptimizedArticle | null;
  draftArticle?: OptimizedArticle | null;
  jobId: string | null;
  isStreaming?: boolean;
  activityText?: string;
}

const exportFiles = ["optimized.md", "optimized.docx", "qa_report.json"];
const streamWords = ["事实", "标题", "结构", "语气", "检索", "改写", "终稿"];
const changedSectionLabels: Record<string, string> = {
  title: "标题优化",
  summary: "摘要优化",
  body: "正文结构与表达",
  body_markdown: "正文结构与表达",
  client_cases: "客户案例",
  social_contribution: "社会价值",
  team_background_claims: "团队背景",
  core_competitiveness_claims: "核心竞争力",
  image_suggestions: "图片建议",
};

export type MarkdownBlock =
  | { type: "heading"; text: string; level: number }
  | { type: "paragraph"; text: string }
  | { type: "list"; items: string[] };

export function OptimizedPreview({
  article,
  draftArticle = null,
  jobId,
  isStreaming = false,
  activityText = "",
}: OptimizedPreviewProps) {
  const [streamTick, setStreamTick] = useState(0);
  const visibleArticle = article ?? draftArticle;
  const bodyMarkdown = visibleArticle?.body_markdown ?? "";
  const markdownBlocks = useMemo(
    () => parseMarkdownBlocks(bodyMarkdown),
    [bodyMarkdown],
  );
  const changedLabels = visibleArticle
    ? getChangedSectionLabels(visibleArticle.changed_sections)
    : [];
  const visibleWordCount = isStreaming ? Math.min(streamTick, 6) : 0;
  const visibleWords = Array.from({ length: visibleWordCount }, (_, offset) => {
    const index = streamTick - visibleWordCount + offset;
    return streamWords[index % streamWords.length];
  });

  useEffect(() => {
    if (!isStreaming) return;

    const timer = window.setInterval(() => {
      setStreamTick((tick) => tick + 1);
    }, 850);

    return () => window.clearInterval(timer);
  }, [isStreaming]);

  if (!visibleArticle && !isStreaming) {
    return (
      <section className="panel empty-panel optimized-panel">
        <div className="panel-heading">优化结果</div>
      </section>
    );
  }

  return (
    <section
      aria-live="polite"
      className={`panel stack optimized-panel ${isStreaming ? "is-streaming" : ""}`}
    >
      <div className="panel-heading">
        <span>优化结果</span>
        {isStreaming && (
          <span className="stream-status">
            <span className="stream-cursor" aria-hidden="true" />
            {activityText || "正在优化"}
          </span>
        )}
      </div>

      {visibleArticle ? (
        <article className={`preview ${isStreaming ? "streaming-preview" : ""}`}>
          <h2>{visibleArticle.title}</h2>
          <p>{visibleArticle.summary}</p>
          <ProgressiveMarkdownPreview
            blocks={markdownBlocks}
            isStreaming={isStreaming}
            key={bodyMarkdown}
          />
        </article>
      ) : (
        <div className="preview stream-placeholder">
          <div className="preview-pulse-line title-line" />
          <div className="preview-pulse-line" />
          <div className="preview-pulse-line short-line" />
          <div className="preview-pulse-block" />
        </div>
      )}

      {isStreaming && visibleWords.length > 0 && (
        <div className="stream-word-row" aria-hidden="true">
          {visibleWords.map((word, index) => (
            <span className="stream-word" key={`${word}-${streamTick}-${index}`}>
              {word}
            </span>
          ))}
        </div>
      )}

      {visibleArticle && (
        <>
          <div>
            <h3>图片建议</h3>
            {visibleArticle.image_suggestions.length > 0 ? (
              <ul>
                {visibleArticle.image_suggestions.map((item) => (
                  <li key={item.source}>
                    <strong>{item.source}</strong>: {item.suggestion}
                  </li>
                ))}
              </ul>
            ) : (
              <p className="empty-panel">暂无图片建议。</p>
            )}
          </div>
          {changedLabels.length > 0 && (
            <div>
              <h3>优化调整</h3>
              <div className="tag-row">
                {changedLabels.map((section) => (
                  <span className="tag" key={section}>
                    {section}
                  </span>
                ))}
              </div>
            </div>
          )}
          {visibleArticle.requires_user_confirmation.length > 0 && (
            <div>
              <h3>需要人工确认</h3>
              <ul>
                {visibleArticle.requires_user_confirmation.map((item) => (
                  <li key={item}>{item}</li>
                ))}
              </ul>
            </div>
          )}
        </>
      )}

      {article && (
        <div className="export-row">
          {exportFiles.map((fileName) =>
            jobId ? (
              <a
                className="download-link"
                href={`/api/jobs/${jobId}/exports/${fileName}`}
                key={fileName}
              >
                {fileName}
              </a>
            ) : (
              <button disabled key={fileName} type="button">
                {fileName}
              </button>
            ),
          )}
        </div>
      )}
    </section>
  );
}

export function parseMarkdownBlocks(markdown: string): MarkdownBlock[] {
  const blocks: MarkdownBlock[] = [];
  const paragraphLines: string[] = [];
  const listItems: string[] = [];

  function flushParagraph() {
    if (paragraphLines.length === 0) return;
    blocks.push({ type: "paragraph", text: paragraphLines.join("\n").trim() });
    paragraphLines.length = 0;
  }

  function flushList() {
    if (listItems.length === 0) return;
    blocks.push({ type: "list", items: [...listItems] });
    listItems.length = 0;
  }

  for (const rawLine of markdown.split(/\r?\n/)) {
    const line = rawLine.trim();
    if (!line) {
      flushParagraph();
      flushList();
      continue;
    }

    const heading = line.match(/^(#{1,6})\s+(.+)$/);
    if (heading) {
      flushParagraph();
      flushList();
      blocks.push({
        type: "heading",
        level: heading[1].length,
        text: heading[2].trim(),
      });
      continue;
    }

    const listItem = line.match(/^[-*]\s+(.+)$/);
    if (listItem) {
      flushParagraph();
      listItems.push(listItem[1].trim());
      continue;
    }

    flushList();
    paragraphLines.push(line);
  }

  flushParagraph();
  flushList();
  return blocks;
}

export function getVisibleMarkdownBlocks(
  blocks: MarkdownBlock[],
  isStreaming: boolean,
  visibleCount: number,
) {
  if (!isStreaming) return blocks;
  return blocks.slice(0, Math.min(Math.max(visibleCount, 1), blocks.length));
}

export function formatChangedSection(section: string) {
  const key = section.trim().toLowerCase().split(":")[0]?.trim() ?? "";
  return changedSectionLabels[key] ?? "其他内容";
}

function getChangedSectionLabels(sections: string[]) {
  return Array.from(new Set(sections.map(formatChangedSection)));
}

function MarkdownPreview({ blocks }: { blocks: MarkdownBlock[] }) {
  if (blocks.length === 0) {
    return <p className="empty-panel">暂无正文内容。</p>;
  }

  return (
    <div className="markdown-preview">
      {blocks.map((block, index) => (
        <MarkdownBlockView block={block} key={`${block.type}-${index}`} />
      ))}
    </div>
  );
}

function ProgressiveMarkdownPreview({
  blocks,
  isStreaming,
}: {
  blocks: MarkdownBlock[];
  isStreaming: boolean;
}) {
  const [visibleCount, setVisibleCount] = useState(1);

  useEffect(() => {
    if (!isStreaming || blocks.length <= 1) return;

    const timer = window.setInterval(() => {
      setVisibleCount((count) => Math.min(count + 1, blocks.length));
    }, 720);

    return () => window.clearInterval(timer);
  }, [blocks.length, isStreaming]);

  return (
    <MarkdownPreview
      blocks={getVisibleMarkdownBlocks(blocks, isStreaming, visibleCount)}
    />
  );
}

function MarkdownBlockView({ block }: { block: MarkdownBlock }) {
  if (block.type === "heading") {
    return (
      <div
        aria-level={Math.min(block.level + 1, 6)}
        className="markdown-heading markdown-block"
        role="heading"
      >
        {renderInlineMarkdown(block.text)}
      </div>
    );
  }

  if (block.type === "list") {
    return (
      <ul className="markdown-list markdown-block">
        {block.items.map((item) => (
          <li key={item}>{renderInlineMarkdown(item)}</li>
        ))}
      </ul>
    );
  }

  return (
    <p className="markdown-paragraph markdown-block">
      {renderInlineMarkdown(block.text)}
    </p>
  );
}

function renderInlineMarkdown(text: string): ReactNode {
  return text.split(/(\*\*[^*]+\*\*)/g).map((part, index) => {
    if (part.startsWith("**") && part.endsWith("**")) {
      return <strong key={index}>{part.slice(2, -2)}</strong>;
    }
    return <Fragment key={index}>{part}</Fragment>;
  });
}
