import { useState, useEffect, useRef, useCallback, useMemo } from 'react';
import { useSearchParams } from 'react-router-dom';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import rehypeRaw from 'rehype-raw';
import type { Components } from 'react-markdown';
import { useAuthStore } from '../lib/auth';
import type { UserRole } from '../types/api';

import globalContent from '../help-content/global.md?raw';
import linguistContent from '../help-content/linguist.md?raw';
import reviewerContent from '../help-content/reviewer.md?raw';
import productionContent from '../help-content/production.md?raw';
import projectManagerContent from '../help-content/project-manager.md?raw';
import adminContent from '../help-content/admin.md?raw';
import faqContent from '../help-content/faq.md?raw';

interface TocEntry {
  level: 2 | 3;
  text: string;
  slug: string;
}

interface Section {
  heading: TocEntry;
  bodyText: string;
}

interface RoleGuide {
  key: string;
  label: string;
  icon: string;
  content: string;
  roles?: UserRole[];
}

const GUIDES: RoleGuide[] = [
  { key: 'global', label: 'Overview', icon: '🌐', content: globalContent },
  { key: 'faq', label: 'FAQ', icon: '❓', content: faqContent },
  { key: 'linguist', label: 'Linguist', icon: '🌍', content: linguistContent, roles: ['linguist'] },
  { key: 'reviewer', label: 'Reviewer', icon: '🔎', content: reviewerContent, roles: ['reviewer'] },
  { key: 'production', label: 'Production', icon: '⚙️', content: productionContent, roles: ['production'] },
  { key: 'project-manager', label: 'Project Manager', icon: '📋', content: projectManagerContent, roles: ['project_manager'] },
  { key: 'admin', label: 'Admin', icon: '👑', content: adminContent, roles: ['admin'] },
];

function slugify(text: string): string {
  return text
    .toLowerCase()
    .replace(/[^\w\s-]/g, '')
    .replace(/\s+/g, '-')
    .replace(/-+/g, '-')
    .trim()
    .replace(/^-+|-+$/g, '');
}

function nodeToText(node: React.ReactNode): string {
  if (typeof node === 'string' || typeof node === 'number') return String(node);
  if (Array.isArray(node)) return node.map(nodeToText).join('');
  if (node && typeof node === 'object' && 'props' in node) {
    return nodeToText((node as React.ReactElement<{ children?: React.ReactNode }>).props.children);
  }
  return '';
}

function extractToc(markdown: string): TocEntry[] {
  const toc: TocEntry[] = [];
  const lines = markdown.split('\n');
  for (const line of lines) {
    const h2 = line.match(/^## (.+)/);
    const h3 = line.match(/^### (.+)/);
    if (h2) {
      const text = h2[1].replace(/\*\*/g, '').replace(/`/g, '').trim();
      toc.push({ level: 2, text, slug: slugify(text) });
    } else if (h3) {
      const text = h3[1].replace(/\*\*/g, '').replace(/`/g, '').trim();
      toc.push({ level: 3, text, slug: slugify(text) });
    }
  }
  return toc;
}

function extractSections(markdown: string): Section[] {
  const lines = markdown.split('\n');
  const sections: Section[] = [];
  let current: TocEntry | null = null;
  let bodyLines: string[] = [];

  const flush = () => {
    if (current) {
      sections.push({
        heading: current,
        bodyText: bodyLines.join(' ').replace(/[#*`_[\]|]/g, ' ').replace(/\s+/g, ' ').toLowerCase(),
      });
      bodyLines = [];
    }
  };

  for (const line of lines) {
    const h2 = line.match(/^## (.+)/);
    const h3 = line.match(/^### (.+)/);
    if (h2 || h3) {
      flush();
      const raw = (h2 ?? h3)![1].replace(/\*\*/g, '').replace(/`/g, '').trim();
      current = { level: h2 ? 2 : 3, text: raw, slug: slugify(raw) };
    } else {
      bodyLines.push(line);
    }
  }
  flush();
  return sections;
}

function defaultRoleKey(role: UserRole | undefined): string {
  if (!role) return 'global';
  const map: Partial<Record<UserRole, string>> = {
    linguist: 'linguist',
    reviewer: 'reviewer',
    production: 'production',
    project_manager: 'project-manager',
    admin: 'global',
  };
  return map[role] || 'global';
}

// Module-scope heading factory — stable identity, no remounts
function makeHeading(level: 1 | 2 | 3 | 4) {
  const Tag = `h${level}` as 'h1' | 'h2' | 'h3' | 'h4';
  const sizeClass =
    level === 1
      ? 'text-3xl font-bold text-gray-900 mb-6 mt-0 pb-4 border-b border-gray-200'
      : level === 2
        ? 'text-xl font-bold text-gray-900 mb-4 mt-8 pt-2'
        : level === 3
          ? 'text-base font-semibold text-gray-800 mb-3 mt-6'
          : 'text-sm font-semibold text-gray-700 mb-2 mt-4';

  return function HeadingComponent({ children, ...props }: React.HTMLAttributes<HTMLHeadingElement>) {
    const text = nodeToText(children);
    const id = text ? slugify(text) : undefined;
    return (
      <Tag id={id} className={sizeClass} {...props}>
        {children}
      </Tag>
    );
  };
}

const HEADING_COMPONENTS = {
  h1: makeHeading(1),
  h2: makeHeading(2),
  h3: makeHeading(3),
  h4: makeHeading(4),
};

export function Help() {
  const { user } = useAuthStore();
  const [searchParams, setSearchParams] = useSearchParams();
  const [activeRole, setActiveRole] = useState<string>(
    searchParams.get('role') || defaultRoleKey(user?.role)
  );
  const [search, setSearch] = useState('');
  const [activeSection, setActiveSection] = useState('');
  const [lightboxSrc, setLightboxSrc] = useState<string | null>(null);
  const [lightboxAlt, setLightboxAlt] = useState<string>('');
  const contentRef = useRef<HTMLDivElement>(null);

  const currentGuide = GUIDES.find(g => g.key === activeRole) || GUIDES[0];
  const toc = useMemo(() => extractToc(currentGuide.content), [currentGuide.content]);
  const sections = useMemo(() => extractSections(currentGuide.content), [currentGuide.content]);

  const filteredToc = useMemo(() => {
    if (!search) return toc;
    const q = search.toLowerCase();
    const matchedSlugs = new Set(
      sections
        .filter(s => s.heading.text.toLowerCase().includes(q) || s.bodyText.includes(q))
        .map(s => s.heading.slug)
    );
    return toc.filter(e => matchedSlugs.has(e.slug));
  }, [toc, sections, search]);

  const handleRoleChange = useCallback(
    (key: string) => {
      setActiveRole(key);
      setSearch('');
      setActiveSection('');
      setSearchParams(prev => {
        const next = new URLSearchParams(prev);
        next.set('role', key);
        return next;
      });
      contentRef.current?.scrollTo({ top: 0, behavior: 'smooth' });
    },
    [setSearchParams]
  );

  useEffect(() => {
    const roleParam = searchParams.get('role');
    if (roleParam && GUIDES.some(g => g.key === roleParam)) {
      setActiveRole(roleParam);
    }
  }, [searchParams]);

  // Scroll-spy — wait one frame for ReactMarkdown to paint headings
  useEffect(() => {
    const root = contentRef.current;
    if (!root) return;

    const observer = new IntersectionObserver(
      entries => {
        for (const entry of entries) {
          if (entry.isIntersecting) {
            setActiveSection(entry.target.id);
            break;
          }
        }
      },
      { root, rootMargin: '-10% 0px -80% 0px', threshold: 0 }
    );

    const raf = requestAnimationFrame(() => {
      root.querySelectorAll('h2[id], h3[id]').forEach(h => observer.observe(h));
    });

    return () => {
      cancelAnimationFrame(raf);
      observer.disconnect();
    };
  }, [currentGuide.content]);

  // Lightbox keyboard close
  useEffect(() => {
    if (!lightboxSrc) return;
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') setLightboxSrc(null);
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [lightboxSrc]);

  const scrollToSection = useCallback((slug: string) => {
    const el = document.getElementById(slug);
    if (el) {
      el.scrollIntoView({ behavior: 'smooth', block: 'start' });
    }
  }, []);

  const openLightbox = useCallback((src: string, alt: string) => {
    setLightboxSrc(src);
    setLightboxAlt(alt);
  }, []);

  const components: Components = useMemo(
    () => ({
      ...HEADING_COMPONENTS,
      p({ children, ...props }) {
        return <p className="text-gray-700 leading-relaxed mb-4" {...props}>{children}</p>;
      },
      ul({ children, ...props }) {
        return <ul className="list-disc list-outside ml-5 mb-4 space-y-1 text-gray-700" {...props}>{children}</ul>;
      },
      ol({ children, ...props }) {
        return <ol className="list-decimal list-outside ml-5 mb-4 space-y-1 text-gray-700" {...props}>{children}</ol>;
      },
      li({ children, ...props }) {
        return <li className="leading-relaxed" {...props}>{children}</li>;
      },
      strong({ children, ...props }) {
        return <strong className="font-semibold text-gray-900" {...props}>{children}</strong>;
      },
      em({ children, ...props }) {
        return <em className="italic text-gray-600" {...props}>{children}</em>;
      },
      code({ children, className, ...props }) {
        const isBlock = className?.includes('language-');
        if (isBlock) {
          return (
            <pre className="bg-gray-900 text-green-400 rounded-lg p-4 mb-4 overflow-x-auto text-sm font-mono">
              <code className={className} {...props}>{children}</code>
            </pre>
          );
        }
        return (
          <code className="bg-gray-100 text-indigo-700 rounded px-1.5 py-0.5 text-sm font-mono" {...props}>
            {children}
          </code>
        );
      },
      blockquote({ children, ...props }) {
        return (
          <blockquote className="border-l-4 border-indigo-400 pl-4 py-1 mb-4 bg-indigo-50 rounded-r-lg" {...props}>
            <div className="text-gray-700">{children}</div>
          </blockquote>
        );
      },
      table({ children, ...props }) {
        return (
          <div className="overflow-x-auto mb-6">
            <table className="min-w-full text-sm border-collapse" {...props}>
              {children}
            </table>
          </div>
        );
      },
      thead({ children, ...props }) {
        return <thead className="bg-indigo-50" {...props}>{children}</thead>;
      },
      th({ children, ...props }) {
        return (
          <th className="px-4 py-2 text-left font-semibold text-indigo-800 border border-gray-200" {...props}>
            {children}
          </th>
        );
      },
      td({ children, ...props }) {
        return (
          <td className="px-4 py-2 text-gray-700 border border-gray-200" {...props}>
            {children}
          </td>
        );
      },
      tr({ children, ...props }) {
        return <tr className="hover:bg-gray-50 transition-colors" {...props}>{children}</tr>;
      },
      hr() {
        return <hr className="my-8 border-gray-200" />;
      },
      a({ href, children, ...props }) {
        return (
          <a
            href={href}
            className="text-indigo-600 hover:text-indigo-800 underline decoration-dotted"
            target={href?.startsWith('http') ? '_blank' : undefined}
            rel={href?.startsWith('http') ? 'noopener noreferrer' : undefined}
            {...props}
          >
            {children}
          </a>
        );
      },
      img({ src, alt }) {
        if (!src) return null;
        // Markdown guides use root-relative paths like /help-screenshots/...
        // Prepend Vite base so they resolve correctly under any subpath deploy.
        const resolvedSrc = src.startsWith('/help-screenshots/')
          ? `${import.meta.env.BASE_URL}${src.slice(1)}`
          : src;
        return (
          <span className="block my-4">
            <button
              type="button"
              className="cursor-zoom-in p-0 border-0 bg-transparent block w-full text-left focus:outline-none focus:ring-2 focus:ring-indigo-400 rounded-xl"
              onClick={() => openLightbox(resolvedSrc, alt ?? '')}
              aria-label={`View full-size: ${alt ?? 'screenshot'}`}
            >
              <img
                src={resolvedSrc}
                alt={alt}
                className="rounded-xl border border-gray-200 shadow-md max-w-full hover:shadow-lg hover:scale-[1.01] transition-all duration-200"
              />
            </button>
            {alt && (
              <span className="block text-center text-xs text-gray-400 mt-1 italic">{alt}</span>
            )}
          </span>
        );
      },
    }),
    [openLightbox]
  );

  return (
    <div className="flex h-full bg-gray-50 overflow-hidden">
      {/* Left rail — role tabs + TOC */}
      <aside className="w-52 flex-shrink-0 bg-white border-r border-gray-200 flex flex-col overflow-y-auto">
        <div className="px-4 py-5 border-b border-gray-100">
          <h2 className="text-sm font-bold text-gray-900 flex items-center gap-2">
            <span className="text-lg">📖</span>
            User Guides
          </h2>
          <p className="text-xs text-gray-400 mt-0.5">Select your role below</p>
        </div>

        <nav aria-label="Role guide selection" className="py-2">
          {GUIDES.map(guide => (
            <button
              key={guide.key}
              type="button"
              onClick={() => handleRoleChange(guide.key)}
              aria-current={activeRole === guide.key ? 'page' : undefined}
              className={`w-full text-left flex items-center gap-2.5 px-4 py-2.5 text-sm transition-colors cursor-pointer focus:outline-none focus:bg-indigo-50 ${
                activeRole === guide.key
                  ? 'bg-indigo-50 text-indigo-700 font-semibold border-r-2 border-indigo-500'
                  : 'text-gray-600 hover:bg-gray-50 hover:text-gray-900'
              }`}
            >
              <span className="text-base" aria-hidden="true">{guide.icon}</span>
              <span className="flex-1">{guide.label}</span>
              {guide.roles && guide.roles.includes(user?.role as UserRole) && (
                <span className="text-xs bg-indigo-100 text-indigo-600 px-1.5 py-0.5 rounded-full">You</span>
              )}
            </button>
          ))}
        </nav>

        {/* TOC */}
        <div className="border-t border-gray-100 px-3 py-3 flex-1">
          <div className="relative mb-2">
            <input
              type="text"
              placeholder="Search guide…"
              value={search}
              onChange={e => setSearch(e.target.value)}
              aria-label="Search guide sections"
              className="w-full text-xs border border-gray-200 rounded-lg px-3 py-1.5 pr-7 focus:outline-none focus:border-indigo-400 bg-gray-50"
            />
            {search && (
              <button
                type="button"
                onClick={() => setSearch('')}
                aria-label="Clear search"
                className="absolute right-2 top-1.5 text-gray-400 hover:text-gray-700 text-xs cursor-pointer"
              >
                ✕
              </button>
            )}
          </div>

          <div className="text-xs font-semibold text-gray-500 uppercase tracking-wide px-1 mb-1">
            Contents
          </div>
          <nav aria-label="Table of contents" className="space-y-0.5 max-h-64 overflow-y-auto">
            {filteredToc.length === 0 && (
              <p className="text-xs text-gray-400 px-1 py-1">No sections found</p>
            )}
            {filteredToc.map(entry => (
              <button
                key={entry.slug}
                type="button"
                onClick={() => scrollToSection(entry.slug)}
                className={`w-full text-left text-xs py-1 px-1 rounded transition-colors truncate cursor-pointer focus:outline-none focus:ring-1 focus:ring-indigo-300 ${
                  entry.level === 3 ? 'pl-3' : ''
                } ${
                  activeSection === entry.slug
                    ? 'text-indigo-600 font-semibold bg-indigo-50'
                    : 'text-gray-500 hover:text-gray-800 hover:bg-gray-50'
                }`}
              >
                {entry.level === 3 && <span className="mr-1 text-gray-300" aria-hidden="true">└</span>}
                {entry.text}
              </button>
            ))}
          </nav>
        </div>
      </aside>

      {/* Main content area */}
      <main
        ref={contentRef}
        className="flex-1 overflow-y-auto"
        id="help-main-content"
        tabIndex={-1}
      >
        <div className="max-w-4xl mx-auto px-8 py-10 pb-24">
          <div className="mb-6 flex items-center gap-3">
            <span className="text-3xl" aria-hidden="true">{currentGuide.icon}</span>
            <div>
              <h1 className="text-2xl font-bold text-gray-900">{currentGuide.label} Guide</h1>
              <p className="text-sm text-gray-400">
                {currentGuide.key === 'global'
                  ? 'Platform overview for all users'
                  : `Step-by-step guide for ${currentGuide.label} role`}
              </p>
            </div>
          </div>

          <div className="bg-white rounded-2xl shadow-sm border border-gray-200 p-8">
            <ReactMarkdown
              remarkPlugins={[remarkGfm]}
              rehypePlugins={[rehypeRaw]}
              components={components}
            >
              {currentGuide.content}
            </ReactMarkdown>
          </div>
        </div>
      </main>

      {/* Lightbox */}
      {lightboxSrc && (
        <div
          role="dialog"
          aria-modal="true"
          aria-label="Image preview"
          className="fixed inset-0 z-50 bg-black/80 flex items-center justify-center p-4"
          onClick={() => setLightboxSrc(null)}
        >
          <div className="relative max-w-6xl max-h-full" onClick={e => e.stopPropagation()}>
            <button
              type="button"
              onClick={() => setLightboxSrc(null)}
              className="absolute -top-10 right-0 text-white text-sm hover:text-gray-300 font-bold cursor-pointer focus:outline-none focus:ring-2 focus:ring-white rounded"
              autoFocus
            >
              ✕ Close (Esc)
            </button>
            <img
              src={lightboxSrc}
              alt={lightboxAlt || 'Screenshot'}
              className="max-w-full max-h-[85vh] rounded-xl shadow-2xl object-contain"
            />
          </div>
        </div>
      )}
    </div>
  );
}
