"use client"

import { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from "react"
import { useTheme } from "next-themes"
import { deriveSecondaryTextColor } from "@/utils/color-utils"

export type ColorPaletteType = {
  name: string
  value: string
  textColor: string
  cssVar: string
  description: string
}

type SystemColorValues = {
  [key: string]: string
}

type ColorContextType = {
  primaryColor: string
  setPrimaryColor: (color: string) => void
  systemColors: SystemColorValues
  setSystemColor: (key: string, value: string) => void
  currentTheme: string | undefined
  updatePaletteImmediately: (palette: {
    primary: string
    backgroundPrimary: { light: string; dark: string }
    backgroundSecondary: { light: string; dark: string }
  }) => { primaryColor: string; bgPrimary: string; bgSecondary: string }
}

/**
 * A simplified color utility class that handles all color conversions and calculations
 */
class ColorUtils {
  /**
   * Converts a hex color string to RGB values
   */
  static hexToRgb(hex: string): { r: number; g: number; b: number } {
    // Remove the # if present
    hex = hex.replace("#", "")

    // Handle both 3-digit and 6-digit hex formats
    const r = hex.length === 3 ? Number.parseInt(hex[0] + hex[0], 16) : Number.parseInt(hex.substring(0, 2), 16)
    const g = hex.length === 3 ? Number.parseInt(hex[1] + hex[1], 16) : Number.parseInt(hex.substring(2, 4), 16)
    const b = hex.length === 3 ? Number.parseInt(hex[2] + hex[2], 16) : Number.parseInt(hex.substring(4, 6), 16)

    return { r, g, b }
  }

  /**
   * Converts RGB values to a hex color string
   */
  static rgbToHex(r: number, g: number, b: number): string {
    return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)
  }

  /**
   * Applies an overlay color to a base color with the specified opacity
   */
  static applyOverlay(baseColor: string, overlayColor: string, opacity: number): string {
    const base = this.hexToRgb(baseColor)
    const overlay = this.hexToRgb(overlayColor)

    // Blend the colors based on opacity
    const r = Math.round(base.r * (1 - opacity) + overlay.r * opacity)
    const g = Math.round(base.g * (1 - opacity) + overlay.g * opacity)
    const b = Math.round(base.b * (1 - opacity) + overlay.b * opacity)

    return this.rgbToHex(r, g, b)
  }

  /**
   * Calculates the luminance of a color (used for determining text color)
   */
  static calculateLuminance(r: number, g: number, b: number): number {
    // Using the relative luminance formula from WCAG
    const normalizedR = r / 255
    const normalizedG = g / 255
    const normalizedB = b / 255
    return 0.2126 * normalizedR + 0.7152 * normalizedG + 0.0722 * normalizedB
  }

  /**
   * Converts RGB values to HSL format
   */
  static rgbToHsl(r: number, g: number, b: number): { h: number; s: number; l: number } {
    r /= 255
    g /= 255
    b /= 255

    const max = Math.max(r, g, b)
    const min = Math.min(r, g, b)
    let h = 0
    let s = 0
    const l = (max + min) / 2

    if (max !== min) {
      const d = max - min
      s = l > 0.5 ? d / (2 - max - min) : d / (max + min)

      switch (max) {
        case r:
          h = (g - b) / d + (g < b ? 6 : 0)
          break
        case g:
          h = (b - r) / d + 2
          break
        case b:
          h = (r - g) / d + 4
          break
      }

      h /= 6
    }

    return {
      h: Math.round(h * 360),
      s: Math.round(s * 100),
      l: Math.round(l * 100),
    }
  }

  /**
   * Determines the appropriate text color (light or dark) based on background color
   */
  static getTextColor(backgroundColor: string, luminanceThreshold = 0.8): string {
    const { r, g, b } = this.hexToRgb(backgroundColor)
    const luminance = this.calculateLuminance(r, g, b)
    return luminance > luminanceThreshold ? "#1a1a1a" : "#ffffff"
  }

  /**
   * Converts a hex color to HSL format
   */
  static hexToHsl(hex: string): { h: number; s: string; l: number } {
    const { r, g, b } = this.hexToRgb(hex)
    return this.rgbToHsl(r, g, b)
  }

  /**
   * Converts HSL to RGB
   */
  static hslToRgb(h: number, s: number, l: number): { r: number; g: number; b: number } {
    h = h / 360
    s = s / 100
    l = l / 100

    const hue2rgb = (p: number, q: number, t: number) => {
      if (t < 0) t += 1
      if (t > 1) t -= 1
      if (t < 1 / 6) return p + (q - p) * 6 * t
      if (t < 1 / 2) return q
      if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6
      return p
    }

    let r, g, b

    if (s === 0) {
      r = g = b = l // achromatic
    } else {
      const q = l < 0.5 ? l * (1 + s) : l + s - l * s
      const p = 2 * l - q
      r = hue2rgb(p, q, h + 1 / 3)
      g = hue2rgb(p, q, h)
      b = hue2rgb(p, q, h - 1 / 3)
    }

    return {
      r: Math.round(r * 255),
      g: Math.round(g * 255),
      b: Math.round(b * 255),
    }
  }

  static calculateBorderColor(backgroundPrimary: string, theme: string | undefined): string {
    const bgColorRgb = ColorUtils.hexToRgb(backgroundPrimary)
    const bgColorLuminance = ColorUtils.calculateLuminance(bgColorRgb.r, bgColorRgb.g, bgColorRgb.b)

    let borderColor: string
    if (theme === "dark") {
      // Dark theme: lighten the background color slightly
      const luminanceIncrease = Math.min(0.08, 1 - bgColorLuminance) // Ensure it doesn't exceed 1
      const newLuminance = bgColorLuminance + luminanceIncrease
      borderColor = ColorUtils.hslToHex(0, 0, newLuminance * 100)
    } else {
      // Light theme: darken the background color slightly
      const luminanceDecrease = Math.min(0.08, bgColorLuminance) // Ensure it doesn't go below 0
      const newLuminance = bgColorLuminance - luminanceDecrease
      borderColor = ColorUtils.hslToHex(0, 0, newLuminance * 100)
    }

    return borderColor
  }

  static hslToHex(h: number, s: number, l: number): string {
    s /= 100
    l /= 100

    let c = (1 - Math.abs(2 * l - 1)) * s,
      x = c * (1 - Math.abs(((h / 60) % 2) - 1)),
      m = l - c / 2,
      r = 0,
      g = 0,
      b = 0

    if (0 <= h && h < 60) {
      r = c
      g = x
      b = 0
    } else if (60 <= h && h < 120) {
      r = x
      g = c
      b = 0
    } else if (120 <= h && h < 180) {
      r = 0
      g = c
      b = x
    } else if (180 <= h && h < 240) {
      r = 0
      g = x
      b = c
    } else if (240 <= h && h < 300) {
      r = x
      g = 0
      b = c
    } else if (300 <= h && h < 360) {
      r = c
      g = 0
      b = x
    }
    // Normalize to 0-255
    r = Math.round((r + m) * 255)
    g = Math.round((g + m) * 255)
    b = Math.round((b + m) * 255)

    return "#" + r.toString(16).padStart(2, "0") + g.toString(16).padStart(2, "0") + b.toString(16).padStart(2, "0")
  }
}

const ColorContext = createContext<ColorContextType | undefined>(undefined)

// Default system colors - updated to match Stripe's aesthetic
const defaultSystemColors = {
  backgroundPrimary: { light: "#ffffff", dark: "#0a0a0a" }, // Changed from pure black
  backgroundSecondary: { light: "#f6f9fc", dark: "#1a3a5f" },
}

/**
 * Provider component for color theming
 */
export function ColorProvider({ children }: { children: ReactNode }) {
  const { theme } = useTheme()
  const [primaryColor, setPrimaryColorState] = useState<string>("#3b82f6") // Base blue
  const [systemColors, setSystemColors] = useState<SystemColorValues>({})
  const [mounted, setMounted] = useState(false)

  // Set mounted state after hydration
  useEffect(() => {
    setMounted(true)
  }, [])

  // Initialize system colors based on theme
  useEffect(() => {
    if (mounted && theme) {
      setSystemColors({
        backgroundPrimary:
          theme === "dark" ? defaultSystemColors.backgroundPrimary.dark : defaultSystemColors.backgroundPrimary.light,
        backgroundSecondary:
          theme === "dark"
            ? defaultSystemColors.backgroundSecondary.dark
            : defaultSystemColors.backgroundSecondary.light,
      })
    }
  }, [mounted, theme])

  /**
   * Calculates the overlay background color based on the background-primary color and theme
   */
  const calculateOverlayBackground = useCallback(
    (backgroundPrimary: string): string => {
      // Apply 2% white overlay in both light and dark mode
      const overlayColor = "#ffffff"
      const overlayOpacity = 0.02 // 2% opacity

      return ColorUtils.applyOverlay(backgroundPrimary, overlayColor, overlayOpacity)
    },
    [theme],
  )

  /**
   * Updates CSS variables based on the selected color and theme
   */
  const updateCssVariables = useCallback(
    (color: string, sysColors: SystemColorValues) => {
      if (typeof window === "undefined") return

      const root = document.documentElement

      // Set primary color as HSL
      const colorHsl = ColorUtils.hexToHsl(color)
      root.style.setProperty("--primary", `${colorHsl.h} ${colorHsl.s}% ${colorHsl.l}%`)
      root.style.setProperty("--ring", `${colorHsl.h} ${colorHsl.s}% ${colorHsl.l}%`)

      // Generate primary color shades
      const primary50 = `${colorHsl.h} ${Math.min(colorHsl.s + 10, 100)}% ${Math.min(colorHsl.l + 45, 95)}%`
      const primary100 = `${colorHsl.h} ${Math.min(colorHsl.s + 5, 100)}% ${Math.min(colorHsl.l + 35, 90)}%`
      const primary200 = `${colorHsl.h} ${colorHsl.s}% ${Math.min(colorHsl.l + 25, 85)}%`
      const primary300 = `${colorHsl.h} ${colorHsl.s}% ${Math.min(colorHsl.l + 15, 80)}%`
      const primary400 = `${colorHsl.h} ${colorHsl.s}% ${Math.min(colorHsl.l + 5, 75)}%`
      const primary500 = `${colorHsl.h} ${colorHsl.s}% ${colorHsl.l}%` // Base color
      const primary600 = `${colorHsl.h} ${colorHsl.s}% ${Math.max(colorHsl.l - 10, 25)}%`
      const primary700 = `${colorHsl.h} ${colorHsl.s}% ${Math.max(colorHsl.l - 20, 20)}%`
      const primary800 = `${colorHsl.h} ${colorHsl.s}% ${Math.max(colorHsl.l - 30, 15)}%`
      const primary900 = `${colorHsl.h} ${colorHsl.s}% ${Math.max(colorHsl.l - 40, 10)}%`

      // Set primary color shade variables
      root.style.setProperty("--primary-50", primary50)
      root.style.setProperty("--primary-100", primary100)
      root.style.setProperty("--primary-200", primary200)
      root.style.setProperty("--primary-300", primary300)
      root.style.setProperty("--primary-400", primary400)
      root.style.setProperty("--primary-500", primary500)
      root.style.setProperty("--primary-600", primary600)
      root.style.setProperty("--primary-700", primary700)
      root.style.setProperty("--primary-800", primary800)
      root.style.setProperty("--primary-900", primary900)

      // Set text color based on luminance
      const textColor = ColorUtils.getTextColor(color, 0.8)
      root.style.setProperty("--primary-text", textColor)

      // Set theme-specific colors
      const themeColors = {
        backgroundPrimary:
          sysColors.backgroundPrimary ||
          (theme === "dark" ? defaultSystemColors.backgroundPrimary.dark : defaultSystemColors.backgroundPrimary.light),
        backgroundSecondary:
          sysColors.backgroundSecondary ||
          (theme === "dark"
            ? defaultSystemColors.backgroundSecondary.dark
            : defaultSystemColors.backgroundSecondary.light),
        textPrimary: theme === "dark" ? "#ffffff" : "#1b1b1b",
        foregroundColor: theme === "dark" ? "#707173" : "#cdcdce",
      }

      // Calculate secondary text color using luminance-based approach
      const secondaryTextColor = deriveSecondaryTextColor(themeColors.textPrimary, themeColors.backgroundPrimary)

      // Apply theme colors
      Object.entries(themeColors).forEach(([key, value]) => {
        const cssVar = `--${key.replace(/([A-Z])/g, "-$1").toLowerCase()}`
        root.style.setProperty(cssVar, value)
      })

      // Set the calculated secondary text color
      root.style.setProperty("--text-secondary", secondaryTextColor)

      // Calculate and set overlay background colors
      const overlayBackground = calculateOverlayBackground(themeColors.backgroundPrimary)
      root.style.setProperty("--input-background", overlayBackground)
      root.style.setProperty("--dropdown-background", overlayBackground)

      // Set border colors based on theme only (not palette-dependent)
      if (theme === "dark") {
        // Dark theme: white with 12% opacity
        root.style.setProperty("--border", "0 0% 100% / 0.12")
        root.style.setProperty("--input", "0 0% 100% / 0.12")
        root.style.setProperty("--separator", "0 0% 100% / 0.06") // Slightly more subtle
      } else {
        // Light theme: black with 12% opacity
        root.style.setProperty("--border", "0 0% 0% / 0.12")
        root.style.setProperty("--input", "0 0% 0% / 0.12")
        root.style.setProperty("--separator", "0 0% 0% / 0.06") // Slightly more subtle
      }
    },
    [theme, calculateOverlayBackground],
  )

  // Add a new direct CSS variable update function that bypasses React state for immediate visual updates:
  const updatePaletteImmediately = useCallback(
    (palette: {
      primary: string
      backgroundPrimary: { light: string; dark: string }
      backgroundSecondary: { light: string; dark: string }
    }) => {
      if (typeof window === "undefined") return

      const root = document.documentElement

      // Get the primary color
      const primaryColor = palette.primary

      // Get theme-specific background colors
      const bgPrimary = theme === "dark" ? palette.backgroundPrimary.dark : palette.backgroundPrimary.light
      const bgSecondary = theme === "dark" ? palette.backgroundSecondary.dark : palette.backgroundSecondary.light

      // Update primary color
      const primaryHsl = ColorUtils.hexToHsl(primaryColor)
      root.style.setProperty("--primary", `${primaryHsl.h} ${primaryHsl.s}% ${primaryHsl.l}%`)
      root.style.setProperty("--ring", `${primaryHsl.h} ${primaryHsl.s}% ${primaryHsl.l}%`)

      // Set text color based on luminance
      const textColor = ColorUtils.getTextColor(primaryColor, 0.8)
      root.style.setProperty("--primary-text", textColor)

      // Update background colors
      root.style.setProperty("--background-primary", bgPrimary)
      root.style.setProperty("--background-secondary", bgSecondary)

      // Calculate primary text color based on theme
      const primaryTextColor = theme === "dark" ? "#ffffff" : "#1b1b1b"

      // Calculate secondary text color using luminance-based approach
      const secondaryTextColor = deriveSecondaryTextColor(primaryTextColor, bgPrimary)
      root.style.setProperty("--text-secondary", secondaryTextColor)

      // Calculate and set overlay background colors
      const overlayBackground = calculateOverlayBackground(bgPrimary)
      root.style.setProperty("--input-background", overlayBackground)
      root.style.setProperty("--dropdown-background", overlayBackground)

      // Set border colors based on theme only (not palette-dependent)
      if (theme === "dark") {
        // Dark theme: white with 12% opacity
        root.style.setProperty("--border", "0 0% 100% / 0.12")
        root.style.setProperty("--input", "0 0% 100% / 0.12")
      } else {
        // Light theme: black with 12% opacity
        root.style.setProperty("--border", "0 0% 0% / 0.12")
        root.style.setProperty("--input", "0 0% 0% / 0.12")
      }

      return { primaryColor, bgPrimary, bgSecondary }
    },
    [theme, calculateOverlayBackground],
  )

  // Custom setPrimaryColor function that also updates CSS variables
  const setPrimaryColor = useCallback(
    (color: string) => {
      setPrimaryColorState(color)
      updateCssVariables(color, systemColors)
    },
    [updateCssVariables, systemColors],
  )

  // Function to set a system color
  const setSystemColor = useCallback(
    (key: string, value: string) => {
      setSystemColors((prev) => {
        const newColors = { ...prev, [key]: value }
        updateCssVariables(primaryColor, newColors)
        return newColors
      })
    },
    [primaryColor, updateCssVariables],
  )

  // Add a new useEffect to handle theme changes and update colors accordingly
  useEffect(() => {
    if (mounted && theme) {
      // Find the current palette by name
      const currentPaletteName = localStorage.getItem("selectedPalette") || "Sage"

      // Distinct color palettes with unique background colors that reflect each palette's character
      const colorPalettes = [
        {
          name: "Sage",
          primary: "#87a96b",
          backgroundPrimary: {
            light: "#fbfcfb", // Subtle green tint
            dark: "#0a0b0a", // Subtle green tint in dark
          },
        },
        {
          name: "Slate",
          primary: "#64748b",
          backgroundPrimary: {
            light: "#fafbfc", // Cool blue-gray tint
            dark: "#0a0a0c", // Cool blue tint in dark
          },
        },
        {
          name: "Terracotta",
          primary: "#c17b5a",
          backgroundPrimary: {
            light: "#fdfbfa", // Warm terracotta tint
            dark: "#0c0a09", // Warm tint in dark
          },
        },
        {
          name: "Navy",
          primary: "#2c3e50",
          backgroundPrimary: {
            light: "#fafbfc", // Cool navy tint
            dark: "#090a0c", // Deep blue tint in dark
          },
        },
        {
          name: "Charcoal",
          primary: "#4a5568",
          backgroundPrimary: {
            light: "#fbfbfb", // Neutral charcoal
            dark: "#0a0a0a", // Pure neutral
          },
        },
        {
          name: "Burgundy",
          primary: "#8b4a6b",
          backgroundPrimary: {
            light: "#fcfafc", // Subtle burgundy tint
            dark: "#0c0a0b", // Warm burgundy tint in dark
          },
        },
        {
          name: "Forest",
          primary: "#4a6741",
          backgroundPrimary: {
            light: "#fafcfa", // Deep forest green tint
            dark: "#0a0c0a", // Forest green tint in dark
          },
        },
        {
          name: "Stone",
          primary: "#8b7d6b",
          backgroundPrimary: {
            light: "#fcfcfb", // Warm stone beige tint
            dark: "#0c0b0a", // Warm stone tint in dark
          },
        },
        {
          name: "Midnight",
          primary: "#2d3748",
          backgroundPrimary: {
            light: "#fafafc", // Deep midnight blue tint
            dark: "#09090c", // Deep midnight tint in dark
          },
        },
        {
          name: "Copper",
          primary: "#b7704f",
          backgroundPrimary: {
            light: "#fdfcfb", // Warm copper tint
            dark: "#0c0b09", // Copper tint in dark
          },
        },
        {
          name: "Pewter",
          primary: "#6b7280",
          backgroundPrimary: {
            light: "#fbfbfc", // Cool pewter gray tint
            dark: "#0a0a0b", // Cool pewter tint in dark
          },
        },
        {
          name: "Olive",
          primary: "#6b7c32",
          backgroundPrimary: {
            light: "#fcfcfa", // Yellow-green olive tint
            dark: "#0b0c0a", // Olive tint in dark
          },
        },
      ]

      // Helper function to calculate secondary background with 12% lightness difference
      const calculateSecondaryBackground = (primaryBg: string, isDark: boolean): string => {
        const primaryHsl = ColorUtils.hexToHsl(primaryBg)
        const lightnessAdjustment = 12 // Increased from 9% to 12% difference

        // Always make secondary darker than primary (parallel relationship)
        const newLightness = Math.max(primaryHsl.l - lightnessAdjustment, 0)

        const { r, g, b } = ColorUtils.hslToRgb(primaryHsl.h, primaryHsl.s, newLightness)
        return ColorUtils.rgbToHex(r, g, b)
      }

      // Find the selected palette
      const selectedPalette = colorPalettes.find((p) => p.name === currentPaletteName)

      if (selectedPalette && currentPaletteName !== "Custom") {
        const primaryBg =
          theme === "dark" ? selectedPalette.backgroundPrimary.dark : selectedPalette.backgroundPrimary.light
        const secondaryBg = calculateSecondaryBackground(primaryBg, theme === "dark")

        // Apply the theme-specific background colors from the selected palette
        setSystemColors((prev) => ({
          ...prev,
          backgroundPrimary: primaryBg,
          backgroundSecondary: secondaryBg,
        }))
      } else {
        // Fallback to default colors if no palette is found or using custom palette
        const primaryBg =
          theme === "dark" ? defaultSystemColors.backgroundPrimary.dark : defaultSystemColors.backgroundPrimary.light
        const secondaryBg = calculateSecondaryBackground(primaryBg, theme === "dark")

        setSystemColors((prev) => ({
          ...prev,
          backgroundPrimary: primaryBg,
          backgroundSecondary: secondaryBg,
        }))
      }
    }
  }, [theme, mounted])

  // Update CSS variables when theme or primary color changes
  useEffect(() => {
    if (mounted) {
      updateCssVariables(primaryColor, systemColors)
    }
  }, [primaryColor, theme, updateCssVariables, mounted, systemColors])

  // Update the contextValue to include the new function
  const contextValue = mounted
    ? {
        primaryColor,
        setPrimaryColor,
        systemColors,
        setSystemColor,
        currentTheme: theme,
        updatePaletteImmediately,
      }
    : {
        primaryColor: "#3b82f6",
        setPrimaryColor: () => {},
        systemColors: {},
        setSystemColor: () => {},
        currentTheme: undefined,
        updatePaletteImmediately: () => ({ primaryColor: "#3b82f6", bgPrimary: "", bgSecondary: "" }),
      }

  return <ColorContext.Provider value={contextValue}>{children}</ColorContext.Provider>
}

/**
 * Hook to access the color context
 */
export function useColorPalette() {
  const context = useContext(ColorContext)
  if (context === undefined) {
    throw new Error("useColorPalette must be used within a ColorProvider")
  }
  return context
}

export const useColor = useColorPalette
