import { useState } from "react";

// Parse content into an array of {type, value, lang, streaming} blocks.
// Handles:
//   - ```lang\ncode``` (well-formed)
//   - ```code```       (no language, no newline — model formatting bug)
//   - ```lang\ncode    (unclosed — streaming in progress)
function parseBlocks(content) {
  const blocks = [];
  let i = 0;

  while (i < content.length) {
    const fenceStart = content.indexOf("```", i);

    if (fenceStart === -1) {
      if (i < content.length) blocks.push({ type: "text", value: content.slice(i) });
      break;
    }

    if (fenceStart > i) blocks.push({ type: "text", value: content.slice(i, fenceStart) });

    let j = fenceStart + 3;
    let lang = "";

    // Language specifier is valid only when word-chars are followed by a newline.
    // If there's no newline (e.g. ```pythonprint(...)) treat everything as code.
    const langMatch = content.slice(j).match(/^(\w+)(\r?\n)/);
    if (langMatch) {
      lang = langMatch[1];
      j += langMatch[0].length;
    } else if (/^\r?\n/.test(content.slice(j))) {
      j += content[j] === "\r" ? 2 : 1;
    }
    // else: no newline — leave j as-is, lang stays ""

    const closeIdx = content.indexOf("```", j);
    if (closeIdx === -1) {
      blocks.push({ type: "code", lang, value: content.slice(j), streaming: true });
      i = content.length;
    } else {
      blocks.push({ type: "code", lang, value: content.slice(j, closeIdx).replace(/\n$/, ""), streaming: false });
      i = closeIdx + 3;
    }
  }

  return blocks;
}

export function Markdown({ content }) {
  if (!content) return null;
  const blocks = parseBlocks(content);
  return (
    <div style={{ lineHeight: "1.6" }}>
      {blocks.map((block, i) =>
        block.type === "code"
          ? <CodeBlock key={i} lang={block.lang} value={block.value} streaming={block.streaming} />
          : <TextBlock key={i} text={block.value} />
      )}
    </div>
  );
}

function CodeBlock({ lang, value, streaming }) {
  const [copied, setCopied] = useState(false);

  const copy = () => {
    navigator.clipboard.writeText(value.trimEnd()).then(() => {
      setCopied(true);
      setTimeout(() => setCopied(false), 1500);
    });
  };

  return (
    <div style={{
      background: "#0d0d0d",
      border: "1px solid #2a2a2a",
      borderRadius: "6px",
      margin: "0.5rem 0",
      overflow: "hidden",
    }}>
      <div style={{
        display: "flex",
        justifyContent: "space-between",
        alignItems: "center",
        padding: "0.3rem 0.75rem",
        background: "#161616",
        borderBottom: "1px solid #2a2a2a",
      }}>
        <span style={{ fontSize: "0.75rem", color: "#666", fontFamily: "monospace" }}>
          {lang || "code"}
          {streaming && <span style={{ color: "#444", marginLeft: "0.5rem" }}>●</span>}
        </span>
        {!streaming && (
          <button onClick={copy} style={{
            background: "transparent",
            border: "none",
            color: copied ? "#4caf50" : "#555",
            cursor: "pointer",
            fontSize: "0.75rem",
            padding: "0.1rem 0.3rem",
          }}>
            {copied ? "Copied!" : "Copy"}
          </button>
        )}
      </div>
      <pre style={{
        padding: "0.75rem 1rem",
        overflowX: "auto",
        fontSize: "0.85rem",
        lineHeight: "1.5",
        margin: 0,
        fontFamily: "monospace",
      }}>
        <code>{value.trimEnd()}</code>
      </pre>
    </div>
  );
}

function TextBlock({ text }) {
  const lines = text.split("\n");
  const elements = [];
  let i = 0;

  while (i < lines.length) {
    const line = lines[i];

    const hMatch = line.match(/^(#{1,3})\s+(.+)/);
    if (hMatch) {
      const level = hMatch[1].length;
      const sizes = { 1: "1.2rem", 2: "1.05rem", 3: "0.95rem" };
      elements.push(
        <div key={i} style={{ fontWeight: "700", fontSize: sizes[level], margin: "0.6rem 0 0.2rem", color: "#fff" }}>
          {inlineMarkdown(hMatch[2])}
        </div>
      );
      i++; continue;
    }

    if (/^[-*]\s+/.test(line)) {
      const items = [];
      while (i < lines.length && /^[-*]\s+/.test(lines[i])) {
        items.push(<li key={i}>{inlineMarkdown(lines[i].replace(/^[-*]\s+/, ""))}</li>);
        i++;
      }
      elements.push(<ul key={`ul-${i}`} style={{ paddingLeft: "1.25rem", margin: "0.25rem 0" }}>{items}</ul>);
      continue;
    }

    if (/^\d+\.\s+/.test(line)) {
      const items = [];
      while (i < lines.length && /^\d+\.\s+/.test(lines[i])) {
        items.push(<li key={i}>{inlineMarkdown(lines[i].replace(/^\d+\.\s+/, ""))}</li>);
        i++;
      }
      elements.push(<ol key={`ol-${i}`} style={{ paddingLeft: "1.25rem", margin: "0.25rem 0" }}>{items}</ol>);
      continue;
    }

    if (/^---+$/.test(line.trim())) {
      elements.push(<hr key={i} style={{ border: "none", borderTop: "1px solid #333", margin: "0.5rem 0" }} />);
      i++; continue;
    }

    if (line.trim() === "") {
      elements.push(<div key={i} style={{ height: "0.4rem" }} />);
      i++; continue;
    }

    elements.push(<div key={i}>{inlineMarkdown(line)}</div>);
    i++;
  }

  return <>{elements}</>;
}

function inlineMarkdown(text) {
  const parts = [];
  const re = /(\*\*(.+?)\*\*|\*(.+?)\*|`([^`]+)`)/g;
  let last = 0;
  let m;

  while ((m = re.exec(text)) !== null) {
    if (m.index > last) parts.push(text.slice(last, m.index));
    if (m[2] !== undefined) {
      parts.push(<strong key={m.index}>{m[2]}</strong>);
    } else if (m[3] !== undefined) {
      parts.push(<em key={m.index}>{m[3]}</em>);
    } else if (m[4] !== undefined) {
      parts.push(
        <code key={m.index} style={{
          background: "#1e1e1e",
          border: "1px solid #333",
          borderRadius: "3px",
          padding: "0.1rem 0.35rem",
          fontSize: "0.85em",
          fontFamily: "monospace",
        }}>
          {m[4]}
        </code>
      );
    }
    last = m.index + m[0].length;
  }

  if (last < text.length) parts.push(text.slice(last));
  return parts.length === 1 && typeof parts[0] === "string" ? parts[0] : parts;
}
