'use client'

import type { GDSComponentProps } from '@graphprotocol/gds-css'
import { createIdenticon, formatAddress, ZERO_ADDRESS } from '@graphprotocol/gds-utils'

import { useCSSPropsPolyfill, useCSSState, useGDS } from '../hooks/index.ts'
import { cn, getCSSPropsAttributes, splitProps } from '../utils/index.ts'
import { AddressMeta } from './Address.meta.ts'
import { Avatar, type AvatarProps } from './Avatar.tsx'
import { MaybeButtonOrLink, type MaybeButtonOrLinkProps } from './base/MaybeButtonOrLink.tsx'
import { CopyButton } from './CopyButton.tsx'

export declare namespace AddressProps {
  interface BaseProps extends GDSComponentProps<typeof AddressMeta> {
    /** The unformatted address (starting with `0x` for EVM) */
    address: string | undefined
    /**
     * Optional avatar image URL. If `undefined` (or an empty string or array), an identicon will be
     * generated from the address. If `null`, no avatar will be rendered.
     */
    avatar?: AvatarProps['src'] | null | undefined
  }
  interface ButtonProps
    extends
      BaseProps,
      MaybeButtonOrLinkProps.ButtonProps,
      MaybeButtonOrLinkProps.DisableableProps {}
  interface LinkProps
    extends BaseProps, MaybeButtonOrLinkProps.LinkProps, MaybeButtonOrLinkProps.DisableableProps {}
  interface OtherElementProps extends BaseProps, MaybeButtonOrLinkProps.OtherElementProps {}
}

export type AddressProps =
  | AddressProps.ButtonProps
  | AddressProps.LinkProps
  | AddressProps.OtherElementProps

export function Address({
  variant,
  size,
  address: passedAddress,
  avatar,
  copy,
  className,
  style,
  children,
  ...props
}: AddressProps) {
  useGDS()

  const { rootProps, nestedProps } = splitProps(props)

  const [stateRef, state] = useCSSState({
    pointer: undefined,
    focus: undefined,
    disabled: Boolean(props.disabled),
    'show-copy': false,
  })
  const [cssPropsPolyfillStateRef, cssPropsPolyfillAttributes] = useCSSPropsPolyfill(
    AddressMeta,
    { variant, size, copy },
    { ref: stateRef },
  )

  const address = passedAddress || ZERO_ADDRESS

  return (
    <span
      ref={cssPropsPolyfillStateRef}
      className={cn(
        `gds-address root-grid *:col-span-full *:row-span-full u:size-max u:max-w-full
        u:state-[show-copy=false]
        u:hover:state-hover
        u:hover:state-[show-copy]
        u:has-copy-button-focus:state-[show-copy]
        u:has-nested-not-clickable/address-ref:cursor-default
        u:has-nested-focus-visible/address-ref:expose-focus
        u:has-nested-active/address-ref:expose-active
        u:has-nested-disabled/address-ref:expose-disabled
        u:can-touch:state-[show-copy]
        u:i:has-copy-button-disabled:state-[show-copy=false]
        u:i:has-nested-not-clickable/address-ref:state-idle`,
        className,
      )}
      {...state.exposedAttributes}
      {...state.polyfillAttributes}
      {...getCSSPropsAttributes(AddressMeta, { variant, size, copy }, style)}
      {...cssPropsPolyfillAttributes}
      {...rootProps}
    >
      <MaybeButtonOrLink
        className={`
          nested/address-ref z-10 outline-0
          @prop-not-variant-enclosed/address:-mx-2
          @prop-not-variant-enclosed/address:-my-1
        `}
        {...nestedProps}
      />
      <span
        data-has-avatar={avatar !== null || undefined}
        className={`
          nested/address-paint flex max-h-full min-h-full items-center
          rounded-full border-transparent ps-(--padding-start) pe-(--padding-end) text-default transition [--padding-end:0px]
          @prop-not-variant-enclosed/address:transition-[color]
          @prop-not-variant-enclosed/address:@state-active/address:text-elevated
          @prop-variant-secondary/address:@state-idle/address:text-muted
          @prop-variant-enclosed/address:border
          @prop-variant-enclosed/address:border-button-secondary-idle
          @prop-variant-enclosed/address:bg-button-secondary-idle
          @prop-variant-enclosed/address:@state-hover/address:border-button-secondary-hover
          @prop-variant-enclosed/address:@state-hover/address:bg-button-secondary-hover
          @prop-variant-enclosed/address:@state-active/address:border-button-secondary-active
          @prop-variant-enclosed/address:@state-active/address:bg-button-secondary-active
          @prop-variant-enclosed/address:@state-disabled/address:border-button-secondary-disabled
          @prop-size-small/address:@prop-variant-enclosed/address:h-6
          @prop-size-small/address:@prop-variant-enclosed/address:[--padding-end:--spacing(1.5)]
          @prop-size-small/address:@prop-variant-enclosed/address:[--padding-start:--spacing(1)]
          @prop-size-medium/address:@prop-variant-enclosed/address:h-8
          @prop-size-medium/address:@prop-variant-enclosed/address:[--padding-end:--spacing(2)]
          @prop-size-medium/address:@prop-variant-enclosed/address:[--padding-start:--spacing(1.5)]
          @prop-size-large/address:@prop-variant-enclosed/address:h-10
          @prop-size-large/address:@prop-variant-enclosed/address:[--padding-end:--spacing(3)]
          @prop-size-large/address:@prop-variant-enclosed/address:[--padding-start:--spacing(2)]
          u:*:transition-opacity
          u:*:@state-disabled/address:opacity-disabled
          u:*:@state-disabled/address:grayscale
          i:not-data-has-avatar:[--padding-start:var(--padding-end)]
          i:@state-active/address:transition-none
          i:@state-disabled/address:text-default
        `}
      >
        <span
          data-has-avatar={avatar !== null || undefined}
          className={`
            absolute inset-0 -m-px rounded-inherit opacity-100 filter-none
            @state-focus/address:outline
            @prop-not-variant-enclosed/address:-mx-2
            @prop-not-variant-enclosed/address:-my-1
            @prop-not-variant-enclosed/address:data-has-avatar:-ms-1
          `}
        />
        {avatar !== null ? (
          <Avatar
            shape="circle"
            src={
              avatar && typeof avatar !== 'string' && !Array.isArray(avatar)
                ? avatar
                : [
                    ...(avatar ? (Array.isArray(avatar) ? avatar : [avatar]) : []),
                    createIdenticon(address),
                  ]
            }
            alt=""
            className={`
              @prop-variant-enclosed/address:-ms-px
              @prop-size-small/address:me-1
              @prop-size-small/address:prop-size-xsmall
              @prop-size-medium/address:me-1.5
              @prop-size-medium/address:prop-size-small
              @prop-size-large/address:me-2
              @prop-size-large/address:prop-size-medium
            `}
          />
        ) : null}
        <span
          className={`
            flex grow
            @prop-size-small/address:text-12
            @prop-size-medium/address:text-14
            @prop-size-large/address:text-16
          `}
        >
          <span
            aria-hidden
            className={`
              truncate transition-opacity
              @prop-copy-auto/address:@state-[show-copy]/address:opacity-0
              @prop-copy-auto/address:@state-[show-copy]/address:delay-50
            `}
          >
            {children || formatAddress(address)}
          </span>
          <span
            className={`
              absolute inset-0 truncate opacity-0 transition-opacity
              @state-not-[show-copy]/address:delay-50
              @state-[show-copy]/address:opacity-100
              @prop-not-copy-auto/address:hidden
              @prop-size-small/address:pe-4.5
              @prop-size-medium/address:pe-5.5
              @prop-size-large/address:pe-6.5
            `}
          >
            {children || formatAddress(address)}
          </span>
        </span>
        <span
          className={`
            my-auto ms-1 -me-px h-max shrink-0 opacity-100 filter-none transition-opacity
            @prop-size-large/address:ms-1.25
            @prop-size-large/address:-me-0.75
            @prop-copy-false/address:hidden
            @prop-copy-auto/address:absolute
            @prop-copy-auto/address:inset-y-0
            @prop-copy-auto/address:end-(--padding-end)
            @prop-copy-auto/address:@state-not-[show-copy]/address:opacity-0
          `}
        >
          <CopyButton
            variant="naked"
            value={formatAddress(address, { style: 'full' })}
            disabled={Boolean(props.disabled)}
            className={`
              z-10
              @prop-size-small/address:prop-size-small
              @prop-size-medium/address:prop-size-medium
              @prop-size-large/address:prop-size-large
            `}
          />
        </span>
      </span>
    </span>
  )
}
