"use client";

import ActionLink from "@/components/ActionLink";
import {
  IconAnchorArrow,
  IconBook,
  IconChart,
  IconChat,
  IconCopy,
  IconFilter,
  IconGraph,
  IconSearch,
} from "@/components/Icons";
import Container from "@/components/NAWebsite/Container";
import * as Accordion from "@radix-ui/react-accordion";
import * as Tabs from "@radix-ui/react-tabs";
import { useState } from "react";
import { Light as SyntaxHighlighter } from "react-syntax-highlighter";
import python from "react-syntax-highlighter/dist/esm/languages/hljs/python";
import sql from "react-syntax-highlighter/dist/esm/languages/hljs/sql";
import { atomOneDark } from "react-syntax-highlighter/dist/esm/styles/hljs";
import { SectionDescription, SectionTitle } from "./Section";

const theme = structuredClone(atomOneDark);
theme["hljs"]["color"] = "#B9C2CA";
theme["hljs"]["background"] = "#06111A";
theme["hljs-comment"]["color"] = "#10b981";

SyntaxHighlighter.registerLanguage("python", python);
SyntaxHighlighter.registerLanguage("sql", sql);

const languages = [
  { name: "Python", code: "python" },
  { name: "SQL", code: "sql" },
];

type Example = {
  icon: React.ReactNode;
  title: string;
  code: Record<
    string,
    {
      code: string;
      highlights?: Set<number>;
    }
  >;
};

export default function PrimaryFeatureSection() {
  const examples: Array<Example> = [
    {
      icon: <IconSearch />,
      title: "Search vector embeddings",
      code: {
        python: {
          code: `
# Define schema
class Doc(Base):
    __tablename__ = "doc"
    id = Column(Integer, primary_key=True)
    content = Column(Text)
    embedding = Column(VectorType(dim=3))

# Create table and index
Base.metadata.create_all(engine)
VectorAdaptor(engine).create_vector_index(
    Doc.embedding, tidb_vector.DistanceMetric.L2
)

# Insert
with Session(engine) as session:
    session.add(Doc(content="dog",  embedding=[1, 2, 1]))
    session.add(Doc(content="fish", embedding=[1, 2, 4]))
    session.commit()

# Search nearest 1 embedding using L2 distance
with Session(engine) as session:
    results = session.execute(
        select(Doc.content)
        .order_by(Doc.embedding.l2_distance([1, 2, 3]))
        .limit(1)
    ).all()
    print(results)
          `,
          highlights: new Set([6, 10, 11, 12, 24, 25]),
        },
        sql: {
          code: `
CREATE TABLE doc(
    content TEXT,
    embedding VECTOR(3),
    VECTOR INDEX ((VEC_L2_DISTANCE(embedding)))
);

INSERT INTO doc VALUES
    ("dog",  "[1, 2, 1]"),
    ("fish", "[1, 2, 4]");

-- Search nearest 1 embedding using L2 distance
SELECT content
    FROM doc
    ORDER BY VEC_L2_DISTANCE(embedding, "[1, 2, 3]")
    LIMIT 1;
          `,
          highlights: new Set([3, 4, 14, 15]),
        },
      },
    },
    {
      icon: <IconFilter />,
      title: "Filter by complex conditions",
      code: {
        python: {
          code: `
# Define schema
class Doc(Base):
    __tablename__ = "doc"
    id = Column(Integer, primary_key=True)
    content = Column(Text)
    kind = Column(Text)
    embedding = Column(VectorType(dim=3))

# Create table and index
Base.metadata.create_all(engine)
VectorAdaptor(engine).create_vector_index(
    Doc.embedding, tidb_vector.DistanceMetric.L2
)

# Insert
with Session(engine) as session:
    session.add(Doc(content="dog",  kind="animal", embedding=[1, 2, 1]))
    session.add(Doc(content="fish", kind="animal", embedding=[1, 2, 4]))
    session.add(Doc(content="tree", kind="plant",  embedding=[1, 2, 3]))
    session.commit()

# Search with any conditions via WHERE clause
with Session(engine) as session:
    results = session.execute(
        select(Doc.content)
        .where(Doc.kind == "animal")
        .order_by(Doc.embedding.l2_distance([1, 2, 3]))
        .limit(1)
    ).all()
    print(results)
          `,
          highlights: new Set([6, 26]),
        },
        sql: {
          code: `
CREATE TABLE doc(
    content TEXT,
    kind TEXT,
    embedding VECTOR(3),
    VECTOR INDEX ((VEC_L2_DISTANCE(embedding)))
);

INSERT INTO doc VALUES
    ("dog",  "animal", "[1, 2, 1]"),
    ("fish", "animal", "[1, 2, 4]"),
    ("tree", "plant",  "[1, 2, 3]");

-- Search with any conditions via WHERE clause
SELECT content
    FROM doc
    WHERE kind = "animal"
    ORDER BY VEC_L2_DISTANCE(embedding, "[1, 2, 3]")
    LIMIT 1;
          `,
          highlights: new Set([3, 16]),
        },
      },
    },
    {
      icon: <IconGraph />,
      title: "Search knowledge graph semantically",
      code: {
        python: {
          code: `
# Schema
class Vertex(Base):
    __tablename__ = "vertices"
    id = Column(Integer, primary_key=True)
    name = Column(Text)

class Edge(Base):
    __tablename__ = "edges"
    id = Column(Integer, primary_key=True)
    source_id = Column(Integer)
    target_id = Column(Integer)
    description = Column(Text)
    description_vec = Column(VectorType(dim=3))

# Insert data here...

# Semantic Search the vertex, then retrieve its source edge and target edge
with Session(engine) as session:
    query_edges = (
        select(Edge)
        .with_only_columns(Edge.source_id, Edge.target_id, Edge.description, Edge.id)
        .order_by(Edge.description_vec.cosine_distance([1, 2, 3]))
        .limit(100)
    ).subquery()

    # Retrieve edge with vertex all at once
    MVertexSource = aliased(Vertex)
    MVertexTarget = aliased(Vertex)
    MEdge = aliased(Edge, query_edges)
    results = session.execute(
        select(MEdge, MVertexSource, MVertexTarget)
        .join(MVertexSource, MVertexSource.id == MEdge.source_id)
        .join(MVertexTarget, MVertexTarget.id == MEdge.target_id)
    )
    for edge, vertexSource, vertexTarget in results:
        print(edge.__dict__, vertexSource.__dict__, vertexTarget.__dict__)
          `,
          highlights: new Set([13, 22, 23]),
        },
        sql: {
          code: `
-- Schema
CREATE TABLE vertices (
  id INT PRIMARY KEY,
  name TEXT
);

CREATE TABLE edges (
  id INT PRIMARY KEY,
  source_id INT,
  target_id INT,
  description TEXT,
  description_vec VECTOR(3),
  VECTOR INDEX ((VEC_COSINE_DISTANCE(description_vec)))
);

-- Insert data here...

-- Semantic Search the vertex, then retrieve its source edge and target edge
SELECT *
FROM (
    SELECT source_id, target_id, description
    FROM edges
    ORDER BY VEC_COSINE_DISTANCE(description_vec, '[1, 2, 3]')
    LIMIT 100
) AS e
INNER JOIN vertices AS source_vertex ON source_vertex.id = e.source_id
INNER JOIN vertices AS target_vertex ON target_vertex.id = e.target_id;
          `,
          highlights: new Set([12, 13, 23, 24]),
        },
      },
    },
    {
      icon: <IconBook />,
      title: "Return search results with text chunks",
      code: {
        python: {
          code: `
# Define schema
class Doc(Base):
    __tablename__ = "doc"
    id = Column(Integer, primary_key=True)
    content = Column(Text)
    embedding = Column(VectorType(dim=3))

# Create table and index
Base.metadata.create_all(engine)
VectorAdaptor(engine).create_vector_index(
    Doc.embedding, tidb_vector.DistanceMetric.L2
)

# Insert
with Session(engine) as session:
    session.add(Doc(content="dog",  embedding=[1, 2, 1]))
    session.add(Doc(content="fish", embedding=[1, 2, 4]))
    session.commit()

# Search
with Session(engine) as session:
    results = session.execute(
        # Retrieve ID and content in the search result,
        # or any other metadata you like
        select(Doc.id, Doc.content)
        .order_by(Doc.embedding.l2_distance([1, 2, 3]))
        .limit(1)
    ).all()
    print(results)
          `,
          highlights: new Set([23, 24, 25]),
        },
        sql: {
          code: `
CREATE TABLE doc(
    content TEXT,
    embedding VECTOR(3),
    VECTOR INDEX ((VEC_L2_DISTANCE(embedding)))
);

INSERT INTO doc VALUES
    ("dog", "[1, 2, 1]"),
    ("fish", "[1, 2, 4]");

-- Retrieve ID and content in the search result,
-- or any other metadata you like
SELECT id, content
    FROM doc
    ORDER BY VEC_L2_DISTANCE(embedding, "[1, 2, 3]")
    LIMIT 1;
          `,
          highlights: new Set([13]),
        },
      },
    },
    {
      icon: <IconChart />,
      title: "Store and analyze RAG feedbacks",
      code: {
        python: {
          code: `
# Schema
class Feedback(Base):
    __tablename__ = "feedback"
    id = Column(Integer, primary_key=True)
    user_id = Column(Integer)
    # Use 0=Like, 1=Dislike. Add index for faster query.
    is_dislike = Column(Integer, index=True)
    chat_context = Column(LONGTEXT)
    timestamp = Column(Integer)

# Insert data here...

# Dig into details of recent 100 dislike feedbacks
with Session(engine) as session:
    results = session.execute(
        select(Feedback)
        .where(Feedback.is_dislike == 1)
        .order_by(Feedback.timestamp.desc())
        .limit(100)
    )
    for obj in results.scalars():
        print(obj.id, obj.user_id, obj.chat_context)

# Plot feedback trends in the last hour
with Session(engine) as session:
    results = session.execute(text("""
        SELECT COUNT(*), FROM_UNIXTIME(FLOOR(timestamp / 60) * 60) AS window_start
        FROM feedback
        WHERE timestamp >= UNIX_TIMESTAMP() - 60 * 60
        AND is_dislike = 1
        GROUP BY window_start
    """)).all()
    print(results)
          `,
        },
        sql: {
          code: `
CREATE TABLE feedback (
  user_id INT,
  is_dislike INT, -- 0=Like, 1=Dislike
  chat_context LONGTEXT,
  timestamp INT,
  INDEX (is_dislike)
);

-- Insert data here...

-- Dig into details of recent 100 dislike feedbacks
SELECT *
  FROM feedback
  WHERE is_dislike = 1
  ORDER BY timestamp DESC
  LIMIT 100;

-- Plot feedback trends in the last hour
SELECT COUNT(*), FROM_UNIXTIME(FLOOR(timestamp / 60) * 60) AS window_start
  FROM feedback
  WHERE
    timestamp >= UNIX_TIMESTAMP() - 60 * 60
    AND is_dislike = 1
  GROUP BY window_start;
          `,
        },
      },
    },
    {
      icon: <IconChat />,
      title: "Secure RAG with built-in access control",
      code: {
        python: {
          code: `
# Define schema
class Doc(Base):
    __tablename__ = "doc"
    id = Column(Integer, primary_key=True)
    owner_id = Column(Integer)
    embedding = Column(VectorType(dim=3))
    content = Column(Text)

# Create table and index
Base.metadata.create_all(engine)
VectorAdaptor(engine).create_vector_index(
    Doc.embedding, tidb_vector.DistanceMetric.L2
)

# Insert
with Session(engine) as session:
    session.add(Doc(owner_id=10, content="dog",  embedding=[1, 2, 1]))
    session.add(Doc(owner_id=10, content="fish", embedding=[1, 2, 4]))
    session.add(Doc(owner_id=17, content="tree", embedding=[1, 0, 0]))
    session.commit()

# Search top 10 similar docs owned by user 17
with Session(engine) as session:
    results = session.execute(
        select(Doc.owner_id, Doc.content)
        .where(Doc.owner_id == 17)
        .order_by(Doc.embedding.l2_distance([1, 2, 3]))
        .limit(10)
    ).all()
    print(results)
          `,
          highlights: new Set([5, 26]),
        },

        sql: {
          code: `
CREATE TABLE doc(
    owner_id INT,
    content TEXT,
    embedding VECTOR(3),
    VECTOR INDEX ((VEC_L2_DISTANCE(embedding)))
);

INSERT INTO doc VALUES
    (10, "dog", "[1, 2, 1]"),
    (10, "fish", "[1, 2, 4]"),
    (17, "tree", "[1, 2, 4]");

-- Search top 10 similar docs owned by user 17
SELECT owner_id, content
    FROM doc
    WHERE owner_id = 17
    ORDER BY VEC_L2_DISTANCE(embedding, "[1, 2, 3]")
    LIMIT 10;
          `,
          highlights: new Set([2, 16]),
        },
      },
    },
  ];

  const [activeLanguage, setActiveLanguage] = useState("python");
  const [activeExample, setActiveExample] = useState("0");

  const [copied, setCopied] = useState(false);

  const handleCopy = async () => {
    try {
      await navigator.clipboard.writeText(
        examples[parseInt(activeExample)].code[activeLanguage]?.code.trim(),
      );
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    } catch (error) {
      console.error("Failed to copy text:", error);
    }
  };

  return (
    <section className="bg-black py-10 md:py-20">
      <a id="features" className="relative top-[-100px]"></a>
      <Container>
        <Tabs.Root
          value={activeExample}
          onValueChange={setActiveExample}
          className="hidden grid-cols-1 lg:grid lg:grid-cols-12 lg:gap-8"
          orientation="vertical"
        >
          <div className="lg:col-span-5">
            <div>
              <SectionTitle>Your AI Stack, Simplified.</SectionTitle>
              <SectionDescription className="my-8">
                TiDB is your complete database solution for AI applications. One
                rules all:
              </SectionDescription>
            </div>
            <Tabs.List aria-label="Features" className="flex flex-col gap-3">
              {examples.map((example, index) => (
                <Tabs.Trigger
                  value={String(index)}
                  key={index}
                  className="text-carbon-500 hover:bg-carbon-900 group relative w-full cursor-pointer select-none font-medium transition-all hover:text-white data-[state=active]:text-white"
                  data-gtag={`event:primary_feature_click,title:${example.title}`}
                >
                  <div className="relative z-10 flex items-center gap-3 p-3 text-left text-xl">
                    <span className="text-xl">{example.icon}</span>
                    <span className="flex-auto">{example.title}</span>
                    <span className="transition-all duration-200 group-data-[state=active]:rotate-45">
                      <IconAnchorArrow className="h-5 w-5" />
                    </span>
                  </div>
                  <div className="bg-violet-medium absolute inset-0 z-0 w-0 w-full opacity-0 transition-all duration-200 group-data-[state=active]:opacity-100"></div>
                </Tabs.Trigger>
              ))}
            </Tabs.List>
            <p className="text-carbon my-8 text-base">
              Say goodbye to data synchronization, duplication, or maintaining
              multiple data stores.
            </p>
          </div>
          <div className="col-span-12 flex flex-col lg:col-span-7">
            {examples.map(
              (example, index) =>
                String(index) === activeExample && (
                  <Tabs.Content
                    value={String(index)}
                    key={index}
                    className="flex flex-1 flex-col content-stretch"
                  >
                    <Tabs.Root
                      value={activeLanguage}
                      onValueChange={setActiveLanguage}
                      className="flex flex-1 flex-col content-stretch"
                    >
                      <Tabs.List className="mb-6 flex flex-row gap-8">
                        {languages.map((language) => (
                          <Tabs.Trigger
                            key={language.code}
                            value={language.code}
                            className="border-carbon-800 text-carbon-800 border-b-2 p-2 px-4 text-base transition-colors hover:border-white hover:text-white data-[state=active]:border-white data-[state=active]:text-white"
                          >
                            {language.name}
                          </Tabs.Trigger>
                        ))}
                      </Tabs.List>
                      {languages.map(
                        (language) =>
                          activeLanguage === language.code && (
                            <Tabs.Content
                              className="TabsContent flex flex-1 flex-col"
                              value={language.code}
                              key={language.code}
                            >
                              <div className="group relative">
                                <button
                                  onClick={handleCopy}
                                  className="absolute right-3 top-4 rounded px-3 py-1 text-sm text-white transition"
                                >
                                  {copied ? "Copied!" : <IconCopy />}
                                </button>
                                <SyntaxHighlighter
                                  language={language.code}
                                  style={theme}
                                  showLineNumbers
                                  wrapLines
                                  customStyle={{
                                    flex: 1,
                                    padding: "24px 16px",
                                  }}
                                  lineNumberStyle={{
                                    opacity: 0.4,
                                  }}
                                  lineProps={(lineNumber) => {
                                    if (
                                      example.code[language.code].highlights &&
                                      example.code[
                                        language.code
                                      ].highlights!.has(lineNumber)
                                    ) {
                                      return {
                                        className:
                                          "bg-yellow-500/20 block text-sm",
                                      };
                                    }
                                    return {
                                      className: "block text-sm",
                                    };
                                  }}
                                >
                                  {example.code[language.code]?.code.trim() ??
                                    ""}
                                </SyntaxHighlighter>
                              </div>
                              <div className="mt-8">
                                <ActionLink
                                  href={`https://docs.pingcap.com/tidbcloud/vector-search-get-started-using-${activeLanguage}`}
                                  target="_blank"
                                  rel="noopener noreferrer"
                                  data-gtag="event:primary_feature_open_doc"
                                >
                                  See Full Documentation
                                </ActionLink>
                              </div>
                            </Tabs.Content>
                          ),
                      )}
                    </Tabs.Root>
                  </Tabs.Content>
                ),
            )}
          </div>
        </Tabs.Root>
        <Accordion.Root
          type="single"
          className="pt-0 md:pt-8 lg:hidden"
          defaultValue="example-0"
        >
          <SectionTitle>Your AI Stack, Simplified.</SectionTitle>
          <SectionDescription className="my-8">
            TiDB is your complete database solution for AI applications. One
            rules all:
          </SectionDescription>
          {examples.map((example, index) => (
            <Accordion.Item value={`example-${index}`} key={index} className="">
              <Accordion.Header>
                <Accordion.Trigger className="text-carbon-500 hover:bg-carbon-900 group relative w-full cursor-pointer select-none font-medium transition-all hover:text-white data-[state=open]:text-white">
                  <div className="relative z-10 flex items-center gap-3 p-3 text-left text-xl">
                    <span className="text-xl">{example.icon}</span>
                    <span className="flex-auto">{example.title}</span>
                    <span className="transition-all duration-200 group-data-[state=open]:rotate-45">
                      <IconAnchorArrow className="h-5 w-5" />
                    </span>
                  </div>
                  <div className="bg-violet-medium absolute inset-0 z-0 w-0 w-full opacity-0 transition-all duration-200 group-data-[state=open]:opacity-100"></div>
                </Accordion.Trigger>
              </Accordion.Header>
              <Accordion.Content className="overflow-hidden leading-6 data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down">
                <Tabs.Root
                  value={activeLanguage}
                  onValueChange={setActiveLanguage}
                  className="flex flex-1 flex-col content-stretch"
                >
                  <Tabs.List className="mb-6 flex flex-row gap-8">
                    {languages.map((language) => (
                      <Tabs.Trigger
                        key={language.code}
                        value={language.code}
                        className="border-carbon-800 text-carbon-800 border-b-2 p-2 px-4 text-base transition-colors hover:border-white hover:text-white data-[state=active]:border-white data-[state=active]:text-white"
                      >
                        {language.name}
                      </Tabs.Trigger>
                    ))}
                  </Tabs.List>
                  {languages.map(
                    (language) =>
                      activeLanguage === language.code && (
                        <Tabs.Content
                          className="TabsContent flex flex-1 flex-col"
                          value={language.code}
                          key={language.code}
                        >
                          <div className="group relative">
                            <button
                              onClick={handleCopy}
                              className="absolute right-3 top-4 rounded px-3 py-1 text-sm text-white transition"
                            >
                              {copied ? "Copied!" : <IconCopy />}
                            </button>
                            <SyntaxHighlighter
                              language={language.code}
                              style={theme}
                              showLineNumbers
                              wrapLines
                              customStyle={{
                                flex: 1,
                                padding: "24px 16px",
                              }}
                              lineNumberStyle={{
                                opacity: 0.4,
                              }}
                              lineProps={(lineNumber) => {
                                if (
                                  example.code[language.code].highlights &&
                                  example.code[language.code].highlights!.has(
                                    lineNumber,
                                  )
                                ) {
                                  return {
                                    className: "bg-yellow-500/20 block text-sm",
                                  };
                                }
                                return {
                                  className: "block text-sm",
                                };
                              }}
                            >
                              {example.code[language.code]?.code.trim() ?? ""}
                            </SyntaxHighlighter>
                          </div>
                          <div className="my-8">
                            <ActionLink
                              href={`https://docs.pingcap.com/tidbcloud/vector-search-get-started-using-${activeLanguage}`}
                              target="_blank"
                              rel="noopener noreferrer"
                              data-gtag="event:primary_feature_open_doc"
                            >
                              See Full Documentation
                            </ActionLink>
                          </div>
                        </Tabs.Content>
                      ),
                  )}
                </Tabs.Root>
              </Accordion.Content>
            </Accordion.Item>
          ))}
        </Accordion.Root>
      </Container>
    </section>
  );
}
