import type { PortalAppearance } from "@shared/appearance";

const backgroundPositionMap = {
  center: "center",
  top: "center top",
  bottom: "center bottom",
  left: "left center",
  right: "right center",
  top_left: "left top",
  top_right: "right top",
  bottom_left: "left bottom",
  bottom_right: "right bottom",
} as const;

function clamp(value: number, min = 0, max = 255) {
  return Math.min(max, Math.max(min, value));
}

function hexToRgb(hex: string) {
  const normalized = hex.replace("#", "");
  const full = normalized.length === 3
    ? normalized.split("").map((char) => `${char}${char}`).join("")
    : normalized;

  const value = Number.parseInt(full, 16);

  return {
    r: (value >> 16) & 255,
    g: (value >> 8) & 255,
    b: value & 255,
  };
}

function rgbToHex(r: number, g: number, b: number) {
  return `#${[r, g, b].map((channel) => clamp(channel).toString(16).padStart(2, "0")).join("")}`;
}

function mix(colorA: string, colorB: string, amount: number) {
  const a = hexToRgb(colorA);
  const b = hexToRgb(colorB);

  return rgbToHex(
    Math.round(a.r + (b.r - a.r) * amount),
    Math.round(a.g + (b.g - a.g) * amount),
    Math.round(a.b + (b.b - a.b) * amount),
  );
}

function withAlpha(hex: string, alpha: number) {
  const { r, g, b } = hexToRgb(hex);
  return `rgba(${r}, ${g}, ${b}, ${alpha})`;
}

function getContrastColor(hex: string) {
  const { r, g, b } = hexToRgb(hex);
  const luminance = (0.2126 * r + 0.7152 * g + 0.0722 * b) / 255;
  return luminance > 0.58 ? "#111827" : "#ffffff";
}

function getFontStack(fontFamily: PortalAppearance["fontFamily"]) {
  switch (fontFamily) {
    case "system":
      return 'Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
    case "rounded":
      return '"Avenir Next", "Nunito Sans", "Segoe UI", system-ui, sans-serif';
    case "serif":
      return '"Iowan Old Style", "Palatino Linotype", "Book Antiqua", Georgia, serif';
    case "marianne":
    default:
      return '"Marianne", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
  }
}

function getButtonRadius(style: PortalAppearance["buttonStyle"]) {
  switch (style) {
    case "pill":
      return "999px";
    case "square":
      return "0.35rem";
    case "rounded":
    default:
      return "0.7rem";
  }
}

function getInputRadius(style: PortalAppearance["inputStyle"]) {
  switch (style) {
    case "filled":
      return "0.95rem";
    case "soft":
      return "0.8rem";
    case "outline":
    default:
      return "0.7rem";
  }
}

function getCardRadius(style: PortalAppearance["cardStyle"]) {
  switch (style) {
    case "outlined":
      return "0.6rem";
    case "elevated":
      return "0.95rem";
    case "soft":
    default:
      return "0.8rem";
  }
}

export function buildAppearanceCssVariables(appearance: PortalAppearance, resolvedTheme: "light" | "dark") {
  const isDark = resolvedTheme === "dark";
  const baseBackground = isDark ? "#0f141a" : "#f7fafc";
  const surfaceBackground = isDark ? "#16202a" : "#eef4f8";
  const cardBackground = isDark ? "#111a22" : "#ffffff";
  const foreground = isDark ? "#edf2f7" : "#14212b";
  const mutedForeground = isDark ? "#a8b5c2" : "#5e6b78";
  const border = isDark ? mix(appearance.secondaryColor, "#0f141a", 0.65) : mix(appearance.secondaryColor, "#d7e2eb", 0.76);
  const input = isDark ? mix(appearance.secondaryColor, "#0f141a", 0.72) : mix(appearance.secondaryColor, "#ffffff", 0.84);

  const primarySoft = mix(appearance.primaryColor, isDark ? "#0f141a" : "#ffffff", isDark ? 0.68 : 0.88);
  const secondarySoft = mix(appearance.secondaryColor, isDark ? "#0f141a" : "#ffffff", isDark ? 0.62 : 0.82);
  const accentSoft = mix(appearance.accentColor, isDark ? "#0f141a" : "#ffffff", isDark ? 0.72 : 0.78);
  const alertSoft = mix(appearance.alertColor, isDark ? "#0f141a" : "#ffffff", isDark ? 0.72 : 0.85);
  const sidebarBackground = appearance.sidebarStyle === "contrast"
    ? mix(appearance.primaryColor, isDark ? "#091018" : "#f4f8fb", isDark ? 0.42 : 0.9)
    : appearance.sidebarStyle === "floating"
      ? cardBackground
      : surfaceBackground;

  const sidebarForeground = appearance.sidebarStyle === "contrast"
    ? getContrastColor(sidebarBackground)
    : foreground;

  const tableStripe = isDark ? withAlpha(appearance.secondaryColor, 0.14) : withAlpha(appearance.secondaryColor, 0.08);
  const cardShadow = appearance.cardStyle === "elevated"
    ? (isDark ? "0 26px 60px rgba(0, 0, 0, 0.42)" : "0 24px 60px rgba(15, 23, 42, 0.12)")
    : appearance.cardStyle === "soft"
      ? (isDark ? "0 12px 28px rgba(0, 0, 0, 0.24)" : "0 10px 24px rgba(15, 23, 42, 0.08)")
      : "0 0 0 rgba(0, 0, 0, 0)";
  const cardHoverShadow = appearance.cardStyle === "elevated"
    ? (isDark ? "0 30px 72px rgba(0, 0, 0, 0.48)" : "0 28px 68px rgba(15, 23, 42, 0.16)")
    : appearance.cardStyle === "soft"
      ? (isDark ? "0 18px 38px rgba(0, 0, 0, 0.3)" : "0 18px 38px rgba(15, 23, 42, 0.12)")
      : "0 10px 24px rgba(15, 23, 42, 0.06)";
  const panelShadow = isDark ? "0 18px 42px rgba(0, 0, 0, 0.28)" : "0 16px 40px rgba(15, 23, 42, 0.09)";
  const panelHoverShadow = isDark ? "0 22px 52px rgba(0, 0, 0, 0.34)" : "0 22px 52px rgba(15, 23, 42, 0.12)";

  const buttonHover = mix(appearance.buttonColor, isDark ? "#ffffff" : "#0f172a", isDark ? 0.12 : 0.08);
  const alertForeground = getContrastColor(appearance.alertColor);
  const backgroundEnabled =
    appearance.backgroundEnabled &&
    (Boolean(appearance.backgroundImageUrl) || Object.values(appearance.backgroundTargetImageUrls || {}).some(Boolean));
  const backgroundOverlay = isDark
    ? `rgba(6, 12, 18, ${appearance.backgroundOverlayOpacity / 100})`
    : `rgba(247, 250, 252, ${appearance.backgroundOverlayOpacity / 100})`;
  const backgroundMode = backgroundEnabled ? appearance.backgroundMode : "cover";
  const backgroundSize = backgroundMode === "repeat" ? "auto" : "cover";
  const backgroundRepeat = backgroundMode === "repeat" ? "repeat" : "no-repeat";
  const backgroundAttachment = backgroundMode === "fixed" ? "fixed" : "scroll";
  const backgroundPosition = backgroundMode === "repeat" ? "top left" : backgroundPositionMap.center;
  const backgroundPresentationMode = appearance.backgroundPresentationMode || "full";
  const backgroundBlur = `${appearance.backgroundBlurRadius || 0}px`;

  return {
    "--primary": appearance.primaryColor,
    "--primary-foreground": getContrastColor(appearance.primaryColor),
    "--secondary": secondarySoft,
    "--secondary-foreground": foreground,
    "--accent": accentSoft,
    "--accent-foreground": foreground,
    "--destructive": appearance.alertColor,
    "--destructive-foreground": alertForeground,
    "--ring": appearance.primaryColor,
    "--sidebar-primary": appearance.primaryColor,
    "--sidebar-primary-foreground": getContrastColor(appearance.primaryColor),
    "--sidebar-accent": appearance.sidebarStyle === "contrast" ? withAlpha("#ffffff", 0.16) : accentSoft,
    "--sidebar-accent-foreground": appearance.sidebarStyle === "contrast" ? "#ffffff" : foreground,
    "--sidebar-ring": appearance.secondaryColor,
    "--sidebar-border": border,
    "--chart-1": appearance.primaryColor,
    "--chart-2": appearance.secondaryColor,
    "--chart-3": appearance.accentColor,
    "--chart-4": mix(appearance.primaryColor, appearance.accentColor, 0.42),
    "--chart-5": mix(appearance.secondaryColor, appearance.primaryColor, 0.58),
    "--background": baseBackground,
    "--foreground": foreground,
    "--card": cardBackground,
    "--card-foreground": foreground,
    "--popover": cardBackground,
    "--popover-foreground": foreground,
    "--muted": surfaceBackground,
    "--muted-foreground": mutedForeground,
    "--border": border,
    "--input": input,
    "--sidebar": sidebarBackground,
    "--sidebar-foreground": sidebarForeground,
    "--success": appearance.primaryColor,
    "--success-foreground": getContrastColor(appearance.primaryColor),
    "--warning": appearance.accentColor,
    "--warning-foreground": getContrastColor(appearance.accentColor),
    "--portal-secondary": appearance.secondaryColor,
    "--portal-secondary-soft": secondarySoft,
    "--portal-primary-soft": primarySoft,
    "--portal-alert-soft": alertSoft,
    "--portal-button": appearance.buttonColor,
    "--portal-button-foreground": getContrastColor(appearance.buttonColor),
    "--portal-button-hover": buttonHover,
    "--portal-table-stripe": tableStripe,
    "--portal-card-shadow": cardShadow,
    "--portal-card-hover-shadow": cardHoverShadow,
    "--portal-panel-shadow": panelShadow,
    "--portal-panel-hover-shadow": panelHoverShadow,
    "--portal-card-radius": getCardRadius(appearance.cardStyle),
    "--portal-button-radius": getButtonRadius(appearance.buttonStyle),
    "--portal-input-radius": getInputRadius(appearance.inputStyle),
    "--portal-motion-fast": "160ms",
    "--portal-motion-base": "220ms",
    "--portal-font-body": getFontStack(appearance.fontFamily),
    "--portal-font-heading": getFontStack(appearance.headingFontFamily),
    "--portal-body-scale": String(appearance.bodyScalePercent / 100),
    "--portal-heading-scale": String(appearance.headingScalePercent / 100),
    "--portal-background-image": backgroundEnabled ? `url("${appearance.backgroundImageUrl}")` : "none",
    "--portal-background-overlay": backgroundOverlay,
    "--portal-background-size": backgroundSize,
    "--portal-background-repeat": backgroundRepeat,
    "--portal-background-attachment": backgroundAttachment,
    "--portal-background-position": backgroundPosition,
    "--portal-background-blur": backgroundBlur,
    "--portal-background-shell-blur": `${Math.min(appearance.backgroundBlurRadius || 0, 2)}px`,
    "--portal-background-shell-attachment": "scroll",
    "--portal-background-presentation-mode": backgroundPresentationMode,
    "--portal-background-center-overlay":
      backgroundPresentationMode === "edge_frame"
        ? (isDark ? "rgba(6, 12, 18, 0.84)" : "rgba(255, 255, 255, 0.88)")
        : (isDark ? "rgba(6, 12, 18, 0.16)" : "rgba(255, 255, 255, 0.12)"),
    "--portal-background-edge-strength":
      backgroundPresentationMode === "edge_frame"
        ? (isDark ? "0.98" : "0.94")
        : (isDark ? "0.28" : "0.22"),
    "--portal-section-tint": withAlpha(appearance.secondaryColor, isDark ? 0.18 : 0.07),
  } satisfies Record<string, string>;
}
