import type { BorderSides, ColorInput } from "@opentui/core"
import type { JSX } from "@opentui/solid"
import { useTheme } from "../../context/theme"
import { createContext, Show, splitProps, useContext } from "solid-js"

export type Axis = "x" | "y"
export type SeparatorEdge = "edge" | "edge-in" | "edge-out"
export type PanelBorder = "start" | "end" | "both" | "none"

const PanelGroupContext = createContext<{ axis: Axis }>()

function crossAxis(axis: Axis) {
  return axis === "x" ? "y" : "x"
}

function usePanelGroup() {
  return useContext(PanelGroupContext)
}

export function PanelGroup(props: JSX.IntrinsicElements["box"] & { axis: Axis }) {
  const [local, boxProps] = splitProps(props, ["axis", "children"])
  return (
    <PanelGroupContext.Provider value={{ axis: local.axis }}>
      <box minWidth={0} minHeight={0} padding={0} flexDirection={local.axis === "x" ? "row" : "column"} {...boxProps}>
        {local.children}
      </box>
    </PanelGroupContext.Provider>
  )
}

export function Panel(props: Omit<JSX.IntrinsicElements["box"], "border"> & { border?: PanelBorder }) {
  const group = usePanelGroup()
  const { theme } = useTheme()
  const [local, boxProps] = splitProps(props, ["border"])
  const border = local.border ?? "start"
  const borderProps =
    border === "none"
      ? {}
      : {
          border: panelBorderSides(group?.axis ?? "y", border),
          borderColor: theme.border,
        }

  return (
    <box
      minWidth={0}
      minHeight={0}
      flexDirection={crossAxis(group?.axis || "y") === "x" ? "row" : "column"}
      {...borderProps}
      {...boxProps}
    />
  )
}

function panelBorderSides(axis: Axis, border: Exclude<PanelBorder, "none">): BorderSides[] {
  if (axis === "x") return border === "both" ? ["top", "bottom"] : [border === "start" ? "top" : "bottom"]
  return border === "both" ? ["left", "right"] : [border === "start" ? "left" : "right"]
}

export function Separator(props: { axis?: Axis; color?: ColorInput; start?: SeparatorEdge; end?: SeparatorEdge }) {
  const group = usePanelGroup()
  const { theme } = useTheme()
  const color = () => props.color ?? theme.border
  const axis = () => props.axis ?? crossAxis(group?.axis ?? "y")
  if (axis() === "y") {
    return (
      <Show
        when={props.start || props.end}
        fallback={<box width={1} flexShrink={0} border={["left"]} borderColor={color()} />}
      >
        <box width={1} flexShrink={0} flexDirection="column">
          <Show when={props.start}>{(edge) => <text fg={color()}>{verticalEdge(edge(), "start")}</text>}</Show>
          <box flexGrow={1} border={["left"]} borderColor={color()} />
          <Show when={props.end}>{(edge) => <text fg={color()}>{verticalEdge(edge(), "end")}</text>}</Show>
        </box>
      </Show>
    )
  }
  return (
    <Show
      when={props.start || props.end}
      fallback={<box height={1} flexShrink={0} border={["top"]} borderColor={color()} />}
    >
      <box height={1} flexShrink={0} flexDirection="row">
        <Show when={props.start}>{(edge) => <text fg={color()}>{horizontalEdge(edge(), "start")}</text>}</Show>
        <box flexGrow={1} border={["top"]} borderColor={color()} />
        <Show when={props.end}>{(edge) => <text fg={color()}>{horizontalEdge(edge(), "end")}</text>}</Show>
      </box>
    </Show>
  )
}

function horizontalEdge(edge: SeparatorEdge, side: "start" | "end") {
  if (edge === "edge") return side === "start" ? "├" : "┤"
  if (edge === "edge-in") return "┴"
  return "┬"
}

function verticalEdge(edge: SeparatorEdge, side: "start" | "end") {
  if (edge === "edge") return side === "start" ? "┬" : "┴"
  if (edge === "edge-in") return "┤"
  return "├"
}
