'use client';

import React, { useEffect, useRef, useState } from 'react';
import { SHOPIFY_STORE_DOMAIN } from '@/services/shopify/client';

const SHOP_JS_URL =
  'https://cdn.shopify.com/shopifycloud/shop-js/modules/v2/loader.pay-button.esm.js';
const TAG_NAME = 'shop-pay-button';
// The hosted element renders at ~43px; reserve it so nothing shifts while shop-js loads.
const MIN_HEIGHT = '43px';
const LOAD_TIMEOUT_MS = 10000;

export interface ShopPayVariant {
  id: string;
  quantity?: number;
}

interface ShopPayButtonProps {
  variants: ShopPayVariant[];
  disabled?: boolean;
  className?: string;
  width?: string;
  borderRadius?: string;
  fallback?: React.ReactNode;
}

let shopJsPromise: Promise<void> | null = null;

function loadShopJs(): Promise<void> {
  if (shopJsPromise) return shopJsPromise;

  shopJsPromise = new Promise<void>((resolve, reject) => {
    if (!document.querySelector(`script[src="${SHOP_JS_URL}"]`)) {
      const script = document.createElement('script');
      script.src = SHOP_JS_URL;
      script.type = 'module';
      script.addEventListener('error', () =>
        reject(new Error('Failed to load the Shop Pay script.'))
      );
      document.head.appendChild(script);
    }

    // Element registration, not script load, is the real readiness signal.
    const timeout = setTimeout(
      () => reject(new Error('Timed out waiting for the Shop Pay button.')),
      LOAD_TIMEOUT_MS
    );
    customElements.whenDefined(TAG_NAME).then(() => {
      clearTimeout(timeout);
      resolve();
    }, reject);
  });

  return shopJsPromise;
}

// Storefront API IDs arrive as GIDs; the web component wants the bare numeric ID.
function toNumericVariantId(id: string): string | null {
  const trimmed = id.trim();
  const gid = trimmed.match(/^gid:\/\/shopify\/ProductVariant\/(\d+)/);
  if (gid) return gid[1];
  return /^\d+$/.test(trimmed) ? trimmed : null;
}

function toVariantsAttribute(variants: ShopPayVariant[]): string | null {
  if (variants.length === 0) return null;

  const parts: string[] = [];
  for (const { id, quantity = 1 } of variants) {
    const numericId = toNumericVariantId(id);
    if (!numericId || !Number.isInteger(quantity) || quantity < 1) return null;
    parts.push(`${numericId}:${quantity}`);
  }
  return parts.join(',');
}

function toStoreUrl(domain?: string): string | null {
  if (!domain) return null;
  try {
    return new URL(domain.startsWith('http') ? domain : `https://${domain}`)
      .origin;
  } catch {
    return null;
  }
}

const ShopPayButton: React.FC<ShopPayButtonProps> = ({
  variants,
  disabled = false,
  className,
  width = '100%',
  borderRadius = '8px',
  fallback = null,
}) => {
  const containerRef = useRef<HTMLDivElement>(null);
  const [status, setStatus] = useState<'loading' | 'ready' | 'error'>(
    'loading'
  );

  const storeUrl = toStoreUrl(SHOPIFY_STORE_DOMAIN);
  const variantsAttribute = toVariantsAttribute(variants);

  useEffect(() => {
    if (!storeUrl || !variantsAttribute) return;

    let cancelled = false;
    loadShopJs().then(
      () => !cancelled && setStatus('ready'),
      () => !cancelled && setStatus('error')
    );

    return () => {
      cancelled = true;
    };
  }, [storeUrl, variantsAttribute]);

  useEffect(() => {
    const container = containerRef.current;
    if (status !== 'ready' || !container || !storeUrl || !variantsAttribute) {
      return;
    }

    const button = document.createElement(TAG_NAME);
    button.setAttribute('store-url', storeUrl);
    button.setAttribute('variants', variantsAttribute);
    button.setAttribute('channel', 'headless');
    if (disabled) button.setAttribute('disabled', '');
    button.style.setProperty('--shop-pay-button-width', width);
    button.style.setProperty('--shop-pay-button-border-radius', borderRadius);
    container.appendChild(button);

    return () => {
      button.remove();
    };
  }, [status, storeUrl, variantsAttribute, disabled, width, borderRadius]);

  if (!storeUrl || !variantsAttribute || status === 'error') {
    return <>{fallback}</>;
  }

  return (
    <div
      ref={containerRef}
      className={className}
      style={{ minHeight: MIN_HEIGHT }}
    />
  );
};

export default ShopPayButton;
