import React, { useEffect, useRef, useState } from "react"
import { render, Text, Box, useApp, useInput } from "ink"

// PDEGO logo rasterized from SVG (circle with P-shaped cutout + center dot)
const LOGO_LINES = [
  "                                              ",
  "               ▄▄████████████▄▄               ",
  "           ▄▄████████████████████▄▄           ",
  "         ▄██████████████████████████▄         ",
  "       ▄██████████████████████████████▄       ",
  "     ▄██████████████████████████████████▄     ",
  "    ██████████████████████████████████████    ",
  "   ████████████████████████▀  █████████████   ",
  "  ▄█████████████████▀▀▀▀▀▀█   █████████████▄  ",
  "  ████████████████▀           ██████████████  ",
  " ▄██████████████▀             ██████████████▄ ",
  " ███████████████     ▄▄▄      ███████████████ ",
  " ███████████████     ████     ███████████████ ",
  " ███████████████              ███████████████ ",
  "  ██████████████            ▄███████████████  ",
  "  ██████████████   ▄      ▄█████████████████  ",
  "   █████████████   ████████████████████████   ",
  "   ▀████████████▄▄████████████████████████▀   ",
  "    ▀████████████████████████████████████     ",
  "      ▀████████████████████████████████▀      ",
  "        ▀████████████████████████████▀        ",
  "          ▀████████████████████████▀          ",
  "             ▀▀████████████████▀▀             ",
  "                  ▀▀▀▀▀▀▀▀▀▀                  ",
]

const FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]

const Spinner = ({ message }: { message: string }) => {
  const [frame, setFrame] = useState(0)
  useEffect(() => {
    const id = setInterval(() => setFrame((f) => (f + 1) % FRAMES.length), 80)
    return () => clearInterval(id)
  }, [])
  return (
    <Text>
      <Text color="cyan">{FRAMES[frame]} </Text>
      {message}
    </Text>
  )
}

export const showSpinner = (message: string) => {
  const app = render(<Spinner message={message} />)
  return async () => {
    app.unmount()
    await app.waitUntilExit()
  }
}

const OneShot = ({ children }: { children: React.ReactNode }) => {
  const { exit } = useApp()
  useEffect(() => {
    exit()
  }, [])
  return <>{children}</>
}

const once = async (node: React.ReactNode) => {
  const app = render(<OneShot>{node}</OneShot>)
  await app.waitUntilExit()
}

const NOISE = ["░", "▒", "▓"]
const TOTAL_FRAMES = 50

const BannerUI = ({
  lines,
  onDone,
}: {
  lines: string[]
  onDone: () => void
}) => {
  const { exit } = useApp()
  const [frame, setFrame] = useState(0)
  const [showSubtitle, setShowSubtitle] = useState(false)

  // Precompute per-character settle frame (diagonal wave left→right, top→bottom)
  const settleTimes = useRef<number[][] | null>(null)
  if (!settleTimes.current) {
    settleTimes.current = lines.map((line, row) =>
      Array.from(line).map((char, col) =>
        char === " "
          ? 0
          : Math.floor(col * 0.65 + row * 0.15 + Math.random() * 10),
      ),
    )
  }

  useEffect(() => {
    if (frame < TOTAL_FRAMES) {
      const id = setTimeout(() => setFrame((f) => f + 1), 20)
      return () => clearTimeout(id)
    }
    const id = setTimeout(() => setShowSubtitle(true), 80)
    return () => clearTimeout(id)
  }, [frame])

  useEffect(() => {
    if (!showSubtitle) return
    const id = setTimeout(() => {
      onDone()
      exit()
    }, 150)
    return () => clearTimeout(id)
  }, [showSubtitle])

  return (
    <Box flexDirection="column" paddingBottom={1}>
      {lines.map((line, row) => (
        <Box key={row} flexDirection="row">
          {Array.from(line).map((char, col) => {
            if (char === " ") return <Text key={col}> </Text>
            const st = settleTimes.current![row][col]
            if (frame >= st) return <Text key={col}>{char}</Text>
            const noise = NOISE[Math.floor((frame * 1.7 + col * 0.9) % 3)]
            return (
              <Text key={col} color="cyan">
                {noise}
              </Text>
            )
          })}
        </Box>
      ))}
      {showSubtitle && (
        <Box marginTop={1} gap={1}>
          <Text bold>Slides Creator</Text>
          <Text dimColor>· make your ideas shine</Text>
        </Box>
      )}
    </Box>
  )
}

export const showBanner = () =>
  new Promise<void>((resolve) => {
    const app = render(<BannerUI lines={LOGO_LINES} onDone={resolve} />)
    app.waitUntilExit().then(() => resolve())
  })

export const showSuccess = (message: string) =>
  once(
    <Box marginTop={1}>
      <Text color="green">✓ </Text>
      <Text>{message}</Text>
    </Box>,
  )

export const showDeleted = (deckName: string) =>
  once(
    <Box marginTop={1}>
      <Text color="red">✕ </Text>
      <Text dimColor>Deleted </Text>
      <Text>{deckName}</Text>
    </Box>,
  )

const relativeTime = (mtimeMs: number): string => {
  const diffMs = Date.now() - mtimeMs
  const diffDays = Math.floor(diffMs / 86_400_000)
  if (diffDays === 0) return "today"
  if (diffDays === 1) return "yesterday"
  if (diffDays < 7) return `${diffDays}d ago`
  const diffWeeks = Math.floor(diffDays / 7)
  if (diffWeeks < 5) return `${diffWeeks}wk ago`
  const diffMonths = Math.floor(diffDays / 30)
  return `${diffMonths}mo ago`
}

type Deck = {
  name: string
  title: string
  description?: string | null
  mtimeMs?: number
}

type DeckPickerResult =
  | { action: "pick"; deck: string }
  | { action: "new" }
  | { action: "delete"; deck: string }

const DeckPickerUI = ({
  custom,
  examples,
  onDone,
}: {
  custom: Deck[]
  examples: Deck[]
  onDone: (result: DeckPickerResult | null) => void
}) => {
  // cursor positions: 0..custom.length-1 → custom decks
  //                   custom.length       → "+ Create"
  //                   custom.length+1..   → examples
  const total = custom.length + 1 + examples.length
  const [cursor, setCursor] = useState(0)
  const { exit } = useApp()

  const done = (result: DeckPickerResult) => {
    onDone(result)
    exit()
  }

  useInput((input, key) => {
    if (key.upArrow) setCursor((c) => (c - 1 + total) % total)
    if (key.downArrow) setCursor((c) => (c + 1) % total)
    if (key.return) {
      if (cursor === custom.length) done({ action: "new" })
      else if (cursor > custom.length)
        done({
          action: "pick",
          deck: examples[cursor - custom.length - 1].name,
        })
      else done({ action: "pick", deck: custom[cursor].name })
    }
    if (key.backspace || key.delete) {
      if (cursor < custom.length)
        done({ action: "delete", deck: custom[cursor].name })
    }
    if (input === "q") {
      onDone(null)
      exit()
    }
  })

  return (
    <Box flexDirection="column" paddingBottom={1}>
      <Text dimColor>Pick a deck</Text>
      <Box flexDirection="column" marginTop={1}>
        {custom.map((deck, i) => (
          <Box key={deck.name} flexDirection="column">
            <Box>
              <Text color={cursor === i ? "cyan" : undefined}>
                {cursor === i ? "› " : "  "}
                {deck.title}
              </Text>
              {cursor === i && <Text dimColor> {deck.name}</Text>}
              {deck.mtimeMs ? (
                <Text dimColor>
                  {"  "}
                  {relativeTime(deck.mtimeMs)}
                </Text>
              ) : null}
            </Box>
            {cursor === i && deck.description && (
              <Text dimColor italic>
                {"  "}
                {deck.description}
              </Text>
            )}
          </Box>
        ))}
        <Box marginTop={1}>
          <Text color={cursor === custom.length ? "cyan" : "dim"}>
            {cursor === custom.length ? "› " : "  "}+ Create a new deck
          </Text>
        </Box>
        {examples.length > 0 && (
          <Box flexDirection="column" marginTop={1}>
            <Text dimColor>— examples —</Text>
            {examples.map((deck, i) => {
              const c = custom.length + 1 + i
              return (
                <Box key={deck.name} flexDirection="column">
                  <Box>
                    <Text color={cursor === c ? "cyan" : undefined}>
                      {cursor === c ? "› " : "  "}
                      {deck.title}
                    </Text>
                    {cursor === c && <Text dimColor> {deck.name}</Text>}
                    {deck.mtimeMs ? (
                      <Text dimColor>
                        {"  "}
                        {relativeTime(deck.mtimeMs)}
                      </Text>
                    ) : null}
                  </Box>
                  {cursor === c && deck.description && (
                    <Text dimColor italic>
                      {"  "}
                      {deck.description}
                    </Text>
                  )}
                </Box>
              )
            })}
          </Box>
        )}
      </Box>
      <Box marginTop={1} gap={1}>
        <Text>↑↓</Text>
        <Text dimColor>navigate</Text>
        <Text>⏎</Text>
        <Text dimColor>open</Text>
        <Text>⌫</Text>
        <Text dimColor>delete</Text>
        <Text>q</Text>
        <Text dimColor>quit</Text>
      </Box>
    </Box>
  )
}

export const pickDeck = async ({
  custom,
  examples,
}: {
  custom: Deck[]
  examples: Deck[]
}): Promise<DeckPickerResult | null> => {
  if (process.stdin.isTTY) process.stdin.setRawMode(true)
  let result: DeckPickerResult | null = null
  const app = render(
    <DeckPickerUI
      custom={custom}
      examples={examples}
      onDone={(r) => {
        result = r
      }}
    />,
  )
  await app.waitUntilExit()
  // Ink calls stdin.unref() on exit, which lets the event loop drain before
  // @inquirer/prompts can attach its own listener. Re-ref to keep it alive,
  // but only when continuing — not when the user quit (result is null).
  if (result) process.stdin.ref()
  return result!
}

const ConfirmUI = ({
  message,
  onDone,
}: {
  message: string
  onDone: (confirmed: boolean) => void
}) => {
  const { exit } = useApp()

  useInput((input, key) => {
    if (input.toLowerCase() === "y") {
      onDone(true)
      exit()
    } else if (input.toLowerCase() === "n" || key.escape || key.return) {
      onDone(false)
      exit()
    }
  })

  return (
    <Box paddingTop={1}>
      <Text dimColor>? </Text>
      <Text>{message} </Text>
      <Text dimColor>(y/N) </Text>
    </Box>
  )
}

export const confirmAction = async (message: string): Promise<boolean> => {
  let result = false
  const app = render(
    <ConfirmUI
      message={message}
      onDone={(r) => {
        result = r
      }}
    />,
  )
  await app.waitUntilExit()
  return result
}

export const showNextSteps = (steps: string[]) =>
  once(
    <Box flexDirection="column" marginTop={1}>
      <Text dimColor>Next steps:</Text>
      {steps.map((step, i) => (
        <Text key={i} color="cyan">
          {"  "}
          {step}
        </Text>
      ))}
    </Box>,
  )
