import type { CSSProperties } from 'react';
import { createTheme, rem } from '@mantine/core';

/**
 * Everything both apps agree on: scale, shape, elevation, and component
 * defaults. No colours — those are the one thing the backoffice and the portal
 * deliberately differ on, so each theme layers its own ramps over this.
 *
 * This began as the portal's theme. The backoffice had no heading scale, no
 * radius scale and no component defaults at all, which is why its features
 * drifted: with nothing to inherit, every page invented its own spacing and
 * sizing. Promoting the portal's structure here fixes 23 features by editing
 * one file, and costs the portal nothing — the values are unchanged.
 */

/**
 * The type stack.
 *
 * Noto Sans Ethiopic sits directly after Inter rather than being swapped in by
 * a `[lang='am']` rule. Browsers fall back per *glyph*, not per element, so one
 * stack renders Latin in Inter and Ge'ez in Noto automatically — including
 * inside a single string. That matters here: a registry is full of mixed-script
 * lines like an Amharic name beside a Latin IMO number, and a language-scoped
 * swap would render one half of those in the wrong face.
 *
 * Inter carries no Ge'ez glyphs at all, so before this the Amharic half of a
 * bilingual system rendered in whatever the OS happened to substitute.
 */
export const EMA_FONT_STACK =
  'Inter, "Noto Sans Ethiopic", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif';

export const baseTheme = createTheme({
  fontFamily: EMA_FONT_STACK,

  headings: {
    fontFamily: EMA_FONT_STACK,
    fontWeight: '700',
    // A little looser than the portal's original values. Ge'ez has taller
    // ascenders and deeper descenders than Latin, so a heading set to Inter's
    // natural leading clips its Amharic rendering — which only became visible
    // once Ethiopic was actually being rendered rather than substituted.
    sizes: {
      h1: { fontSize: rem(32), lineHeight: '1.3' },
      h2: { fontSize: rem(25), lineHeight: '1.35' },
      h3: { fontSize: rem(21), lineHeight: '1.4' },
      h4: { fontSize: rem(17), lineHeight: '1.45' },
      h5: { fontSize: rem(15), lineHeight: '1.5' },
    },
  },

  defaultRadius: 'md',
  radius: {
    xs: rem(6),
    sm: rem(8),
    md: rem(12),
    lg: rem(16),
    xl: rem(22),
  },

  shadows: {
    xs: '0 1px 2px rgba(15,23,42,0.06)',
    sm: '0 2px 8px rgba(15,23,42,0.06), 0 1px 2px rgba(15,23,42,0.04)',
    md: '0 8px 24px rgba(15,23,42,0.08)',
    lg: '0 16px 40px rgba(15,23,42,0.12)',
    xl: '0 24px 64px rgba(15,23,42,0.16)',
  },

  breakpoints: {
    xs: '36em',
    sm: '48em',
    md: '62em',
    lg: '75em',
    xl: '88em',
  },

  cursorType: 'pointer',

  // Draw a focus ring for keyboard users only. The codebase had no
  // `:focus-visible` handling anywhere, which is the single largest WCAG gap.
  focusRing: 'auto',

  // Shade 6 in light. The dark counterpart is deliberately left unset until
  // dark mode is verified end to end — changing it moves every filled control.
  primaryShade: { light: 6 },

  components: {
    Paper: { defaultProps: { radius: 'lg' } },
    Card: { defaultProps: { radius: 'lg' } },
    Button: {
      defaultProps: { radius: 'md' },
      styles: { root: { fontWeight: 600 } },
    },
    Badge: { defaultProps: { radius: 'sm' } },
    ThemeIcon: { defaultProps: { radius: 'md' } },
    NavLink: { styles: { root: { borderRadius: rem(10), fontWeight: 500 } } },
    TextInput: { defaultProps: { radius: 'md' } },
    Textarea: { defaultProps: { radius: 'md' } },
    Select: { defaultProps: { radius: 'md' } },
    PasswordInput: { defaultProps: { radius: 'md' } },

    // The page sits on a tinted surface and cards float on white. Without this
    // the main area is the same white as every Paper on it, and the card
    // borders are the only thing separating content from chrome.
    AppShell: {
      styles: { main: { background: 'var(--ema-surface-page)' } },
    },

    // Tables — the registry look: quiet uppercase headers, hairline row
    // borders, a tint on hover, no zebra striping and no column rules. Set
    // once here so the 14 pages rendering a raw <Table> match the 28 that go
    // through AdvancedTable instead of each picking their own density.
    //
    // Header text is `text-secondary` rather than the lighter dimmed gray the
    // mockup used: at 11px uppercase, gray-5 on white fails 4.5:1.
    Table: {
      defaultProps: { highlightOnHover: true, verticalSpacing: 'sm', horizontalSpacing: 'md' },
      styles: {
        table: {
          '--table-border-color': 'var(--ema-border-subtle)',
          '--table-hover-color': 'var(--ema-surface-page)',
          '--table-striped-color': 'var(--ema-surface-sunken)',
        } as CSSProperties,
        th: {
          fontSize: rem(11),
          fontWeight: 700,
          textTransform: 'uppercase',
          letterSpacing: '0.05em',
          color: 'var(--ema-text-secondary)',
          whiteSpace: 'nowrap',
        },
        td: { fontSize: rem(13) },
      },
    },

    // Mantine's stock scroll wrapper (NativeScrollArea) discards the
    // max-height it's handed unless scrollAreaComponent is set, so a modal
    // taller than the viewport just gets clipped with no way to scroll it.
    // Making the body the scrollport here fixes every Modal/Drawer at once.
    Modal: {
      styles: {
        content: { display: 'flex', flexDirection: 'column', maxHeight: '90dvh' },
        body: { flex: '1 1 auto', minHeight: 0, overflowY: 'auto' },
      },
    },
    Drawer: {
      styles: {
        content: { display: 'flex', flexDirection: 'column' },
        body: { flex: '1 1 auto', minHeight: 0, overflowY: 'auto' },
      },
    },
  },

  other: {
    heroGradient: 'linear-gradient(135deg, #3160b7 0%, #1fc29d 100%)',
  },
});
