import {
  DeesElement,
  html,
  property,
  customElement,
  css,
  type TemplateResult,
} from '@design.estate/dees-element';
import * as lucideIcons from 'lucide';
import {
  Activity,
  ArrowUp,
  Bell,
  Bolt,
  Box,
  Building2,
  Check,
  ChevronDown,
  ChevronRight,
  Clock,
  Cloud,
  Copy,
  CreditCard,
  Fingerprint,
  Globe,
  Grid2x2,
  Home,
  Key,
  Laptop,
  Lock,
  LogOut,
  Mail,
  MapPin,
  Monitor,
  MonitorSmartphone,
  Nfc,
  Phone,
  Plus,
  Power,
  QrCode,
  Search,
  Settings,
  Shield,
  SmartphoneNfc,
  SquarePen,
  Trash2,
  TriangleAlert,
  User,
  Users,
  Wallet,
  X,
  createElement,
  type IconNode,
} from 'lucide';
import { idpElementStyles } from './tokens.js';

export type TIdpIconName =
  | 'activity'
  | 'alert'
  | 'alert-triangle'
  | 'arrow-up'
  | 'bell'
  | 'bolt'
  | 'box'
  | 'building'
  | 'building2'
  | 'building-2'
  | 'check'
  | 'chevron'
  | 'chevron-down'
  | 'chevron-right'
  | 'clock'
  | 'cloud'
  | 'copy'
  | 'credit'
  | 'device'
  | 'edit'
  | 'fingerprint'
  | 'gear'
  | 'globe'
  | 'grid'
  | 'home'
  | 'key'
  | 'laptop'
  | 'location'
  | 'lock'
  | 'logout'
  | 'mail'
  | 'monitor'
  | 'monitor-smartphone'
  | 'nfc'
  | 'phone'
  | 'plus'
  | 'power'
  | 'qr'
  | 'search'
  | 'settings'
  | 'shield'
  | 'smartphone-nfc'
  | 'trash'
  | 'user'
  | 'users'
  | 'wallet'
  | 'waveform'
  | 'x'
  | `lucide:${string}`;

declare global {
  interface HTMLElementTagNameMap {
    'idp-icon': IdpIcon;
  }
}

const iconNodes: Record<string, IconNode> = {
  activity: Activity,
  alert: TriangleAlert,
  'alert-triangle': TriangleAlert,
  'arrow-up': ArrowUp,
  bell: Bell,
  bolt: Bolt,
  box: Box,
  building: Building2,
  building2: Building2,
  'building-2': Building2,
  check: Check,
  chevron: ChevronRight,
  'chevron-down': ChevronDown,
  'chevron-right': ChevronRight,
  clock: Clock,
  cloud: Cloud,
  copy: Copy,
  credit: CreditCard,
  device: MonitorSmartphone,
  edit: SquarePen,
  fingerprint: Fingerprint,
  gear: Settings,
  globe: Globe,
  grid: Grid2x2,
  home: Home,
  key: Key,
  laptop: Laptop,
  location: MapPin,
  lock: Lock,
  logout: LogOut,
  mail: Mail,
  monitor: Monitor,
  'monitor-smartphone': MonitorSmartphone,
  nfc: Nfc,
  phone: Phone,
  plus: Plus,
  power: Power,
  qr: QrCode,
  search: Search,
  settings: Settings,
  shield: Shield,
  'smartphone-nfc': SmartphoneNfc,
  trash: Trash2,
  user: User,
  users: Users,
  wallet: Wallet,
  waveform: Activity,
  x: X,
};

const toKebab = (valueArg: string): string => valueArg
  .replace(/^lucide:/, '')
  .replace(/([a-z0-9])([A-Z])/g, '$1-$2')
  .toLowerCase();

const toLucideExportName = (valueArg: string): string => valueArg
  .replace(/^lucide:/i, '')
  .split(/[-_: ]+/)
  .filter(Boolean)
  .map((partArg) => `${partArg.charAt(0).toUpperCase()}${partArg.slice(1)}`)
  .join('');

@customElement('idp-icon')
export class IdpIcon extends DeesElement {
  public static demo = () => html`<idp-icon name="shield"></idp-icon>`;
  public static demoGroups = ['idp.global v3 primitives'];

  @property({ type: String })
  public accessor name: TIdpIconName = 'shield';

  @property({ type: Number })
  public accessor size = 18;

  private lastRenderKey = '';

  public static styles = [
    ...idpElementStyles,
    css`
      :host {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        color: currentColor;
        line-height: 0;
        vertical-align: middle;
      }
      #iconContainer {
        width: var(--icon-size);
        height: var(--icon-size);
      }
      #iconContainer svg {
        display: block;
        width: 100%;
        height: 100%;
        fill: none;
        stroke: currentColor;
        stroke-width: 1.75;
        stroke-linecap: round;
        stroke-linejoin: round;
      }
    `,
  ];

  private resolveIconNode(): IconNode {
    const rawName = String(this.name || 'shield');
    const iconName = toKebab(rawName);
    const aliasNode = iconNodes[iconName];
    if (aliasNode) {
      return aliasNode;
    }

    const exportName = toLucideExportName(rawName);
    const lucideNode = (lucideIcons as Record<string, unknown>)[exportName];
    if (Array.isArray(lucideNode)) {
      return lucideNode as IconNode;
    }

    return Shield;
  }

  public render(): TemplateResult {
    return html`
      <div id="iconContainer" style="--icon-size: ${this.size}px"></div>
    `;
  }

  public updated(): void {
    const renderKey = `${this.name}:${this.size}`;
    if (this.lastRenderKey === renderKey) {
      return;
    }

    this.lastRenderKey = renderKey;

    const container = this.shadowRoot?.querySelector('#iconContainer');
    if (!container) {
      return;
    }

    container.innerHTML = '';
    const iconElement = createElement(this.resolveIconNode(), {
      color: 'currentColor',
      size: this.size,
      strokeWidth: 1.75,
    });
    iconElement.setAttribute('aria-hidden', 'true');
    container.appendChild(iconElement);
  }
}
