import React, { forwardRef, SyntheticEvent, useEffect, useState } from 'react';

import { useWebMergeStyles } from '@cleartrip/ct-design-style-manager';
import type { Styles } from '@cleartrip/ct-design-types';

import NextImage from 'next/image';

import { IImageProps, IImageWebRendererProps } from './type';
import staticImageStyles from './style';

/**
 * Default web renderer. Emits a plain `<img>` so the design-system
 * package stays framework-agnostic. Consumers that want `next/image`
 * (or any other image optimizer) can inject it via the `Component`
 * prop — the injected component is handed the same minimal surface
 * described by `IImageWebRendererProps`.
 */
const DefaultImgComponent = forwardRef<HTMLImageElement, IImageWebRendererProps>(
  ({ src, alt, width, height, className, onClick, onLoad, onError }, ref) => (
    <img
      ref={ref}
      src={src}
      alt={alt}
      width={width}
      height={height}
      className={className}
      onClick={onClick}
      onLoad={onLoad}
      onError={onError}
    />
  ),
);

DefaultImgComponent.displayName = 'ImageDefaultRenderer';

const NextImageComponent = forwardRef<HTMLImageElement, IImageWebRendererProps>(
  (
    {
      src,
      alt,
      width,
      height,
      className,
      onClick,
      onLoad,
      onError,
      priority,
      loading,
      blurDataURL,
      unoptimized,
      fetchPriority,
    },
    ref,
  ) => (
    <NextImage
      ref={ref}
      src={src}
      alt={alt}
      width={width}
      height={height}
      className={className}
      onClick={onClick}
      onLoad={onLoad}
      onError={onError}
      priority={priority}
      loading={loading}
      blurDataURL={blurDataURL}
      unoptimized={unoptimized}
      fetchPriority={fetchPriority}
    />
  ),
);

NextImageComponent.displayName = 'NextImageComponent';
/**
 * Web implementation of `Image`.
 *
 * Migrated from yagami (aldenui) per `Migration.MD`:
 *   - `next/image` coupling dropped; the renderer is injectable via
 *     the `Component` prop (defaults to a semantic `<img>`).
 *   - `useWebMergeStyles` composes caller-provided `styleConfig.root`
 *     slots into a single className string handed to the renderer.
 *   - Fallback-URL handling mirrors the yagami behavior bit-for-bit:
 *     initial `src || fallbackUrl`, and onError swaps in `fallbackUrl`
 *     once (guarded by `imageSource !== fallbackUrl` to prevent an
 *     infinite error loop when the fallback itself 404s).
 *
 * The ref is forwarded to the underlying `HTMLImageElement` so
 * consumers can still measure or imperatively trigger loads.
 */
const Image = forwardRef<HTMLImageElement, IImageProps>(
  (
    {
      src,
      alt,
      width,
      height,
      fallbackUrl,
      styleConfig,
      onClick,
      onLoad,
      onError,
      Component,
      priority,
      loading,
      blurDataURL,
      unoptimized,
      fetchPriority,
    },
    ref,
  ) => {
    const [imageSource, setImageSource] = useState<string>(src || fallbackUrl || '');

    const { root: customRootStyles = [] } = styleConfig || {};

    // Note: customRootStyles is a `ViewStyle`-shaped array; the
    // style-manager flattens it into real CSS at resolution time.
    const mergedRootClassName = useWebMergeStyles(
      [staticImageStyles.root as Styles, ...(customRootStyles as unknown as Styles[])],
      [staticImageStyles.root, customRootStyles],
    );

    useEffect(() => {
      setImageSource(src || fallbackUrl || '');
    }, [fallbackUrl, src]);

    const onImageError = (e: SyntheticEvent<HTMLImageElement, Event>) => {
      if (fallbackUrl && imageSource !== fallbackUrl) {
        setImageSource(fallbackUrl);
      }
      if (onError) {
        onError(e);
      }
    };

    // The default renderer is a `forwardRef`-ed `<img>` so the ref
    // passes straight through. User-injected renderers SHOULD also be
    // forwardRef-wrapped (next/image is); we widen the type here so
    // the `ref` attribute is accepted unconditionally.
    const Renderer = (Component || NextImageComponent) as React.ComponentType<
      IImageWebRendererProps & { ref?: React.Ref<HTMLImageElement> }
    >;

    return (
      <Renderer
        ref={ref}
        src={imageSource}
        alt={alt}
        width={width as number}
        height={height as number}
        className={mergedRootClassName}
        onClick={onClick}
        onLoad={onLoad}
        onError={onImageError}
        priority={priority}
        loading={loading}
        blurDataURL={blurDataURL}
        unoptimized={unoptimized}
        fetchPriority={fetchPriority}
      />
    );
  },
);

Image.displayName = 'Image';

export default Image;
