// Copyright © 2022 Olo Inc. All rights reserved.
// This software is made available under the Olo Pay SDK License (See LICENSE.md file)
import React, { useCallback, useImperativeHandle } from 'react';
import { forwardRef, useRef } from 'react';
import {
  type HostComponent,
  type NativeSyntheticEvent,
  Platform,
  StyleSheet,
  View,
} from 'react-native';
import {
  CardField,
  type CardValidationStatus,
  type OloError,
  type PaymentCardDetailsFormMethods,
  type PaymentCardDetailsFormProps,
  type PaymentMethod,
  type PaymentMethodResult,
} from '../definitions';
import type { CardDetailsNativeProps } from 'src/components/definitions/PaymentCardDetailsFormNativeTypes';

import usePaymentCardDetailsFormManager from '../hooks/usePaymentCardDetailsFormManager';

import { sharedComponentStyles } from './styles/sharedStyles';
import { sharedComponentValues } from './definitions/sharedValues';

// Fabric-only architecture
const CardDetailsNative: HostComponent<CardDetailsNativeProps> =
  require('./specs/PaymentCardDetailsFormNativeComponent').default;

export const PaymentCardDetailsForm = forwardRef<
  PaymentCardDetailsFormMethods,
  PaymentCardDetailsFormProps
>(
  (
    {
      cardStyles,
      componentStyles,
      disabled,
      onFormComplete,
      onPaymentMethodResult,
      viewProps,
      placeholders,
      ...props
    },
    ref: any
  ) => {
    const ViewManagerMethods = usePaymentCardDetailsFormManager();
    const inputRef = useRef(null);

    const onFormCompleteEventHandler = useCallback(
      (event: NativeSyntheticEvent<CardValidationStatus>) => {
        const cardEvent = event.nativeEvent;

        const formComplete: CardValidationStatus = {
          isValid: cardEvent.isValid,
        };

        onFormComplete?.(formComplete);
      },
      [onFormComplete]
    );

    // Handle payment method result event
    const onPaymentMethodResultHandler = useCallback((event: NativeSyntheticEvent<{paymentMethod?: PaymentMethod; error?: OloError}>) => {
      const eventData = event.nativeEvent;

      // Check for actual content (Fabric may send empty objects for unset optionals)
      const hasError = eventData.error?.code || eventData.error?.message;
      const hasPaymentMethod = eventData.paymentMethod?.id;

      // Normalize the result - only include error/paymentMethod if they have actual content
      const normalizedResult: PaymentMethodResult = {
        ...(hasPaymentMethod ? { paymentMethod: eventData.paymentMethod } : {}),
        ...(hasError ? { error: eventData.error } : {}),
      };

      onPaymentMethodResult?.(normalizedResult);
    }, [onPaymentMethodResult]);

    const createPaymentMethod = (): void => {
      ViewManagerMethods.createPaymentMethod(inputRef);
    };

    const blur = (): void => {
      ViewManagerMethods.blur(inputRef);
    };

    const clear = (): void => {
      ViewManagerMethods.clear(inputRef);
    };

    const focus = (field: CardField = CardField.number): void => {
      ViewManagerMethods.focus(inputRef, field);
    };

    useImperativeHandle(ref, () => ({
      blur,
      clear,
      createPaymentMethod,
      focus,
    }));

    return (
      <View style={componentStyles} {...viewProps}>
        <CardDetailsNative
          style={[defaultStyles.cardDetailsForm, cardStyles?.styles]}
          ref={inputRef}
          onFormCompleteEvent={onFormCompleteEventHandler}
          onPaymentMethodResultEvent={onPaymentMethodResultHandler}
          isEnabled={!disabled}
          placeholders={{
            number:
              placeholders?.number ??
              sharedComponentValues.defaultValues.formNumberPlaceholder,
            expiration:
              placeholders?.expiration ??
              sharedComponentValues.defaultValues.expirationPlaceholder,
            cvv:
              placeholders?.cvv ??
              sharedComponentValues.defaultValues.cvvPlaceholder,
            postalCode:
              placeholders?.postalCode ??
              sharedComponentValues.defaultValues.postalCodePlaceholder,
          }}
          cardStyles={{
            backgroundColor:
              cardStyles?.backgroundColor ??
              sharedComponentStyles.defaultStyles.backgroundColor,
            cursorColor:
              cardStyles?.cursorColor ??
              sharedComponentStyles.defaultStyles.cursorColor,
            // Android Only
            borderColor:
              cardStyles?.borderColor ??
              sharedComponentStyles.defaultStyles.borderColor,
            borderWidth:
              cardStyles?.borderWidth ??
              sharedComponentStyles.defaultStyles.borderWidth,
            cornerRadius:
              cardStyles?.cornerRadius ??
              sharedComponentStyles.defaultStyles.cornerRadius,
            textColor:
              cardStyles?.textColor ??
              sharedComponentStyles.defaultStyles.textColor,
            placeholderColor:
              cardStyles?.placeholderColor ??
              sharedComponentStyles.defaultStyles.placeholderColor,
            fontSize:
              cardStyles?.fontSize ??
              sharedComponentStyles.defaultStyles.fontSize,
            textPaddingLeft:
              cardStyles?.textPaddingLeft ??
              sharedComponentStyles.defaultStyles.paddingLeft,
            textPaddingRight:
              cardStyles?.textPaddingRight ??
              sharedComponentStyles.defaultStyles.paddingRight,
            fieldDividerColor:
              cardStyles?.fieldDividerColor ??
              sharedComponentStyles.defaultStyles.dividerColor,
            fieldDividerWidth:
              cardStyles?.fieldDividerWidth ??
              sharedComponentStyles.defaultStyles.dividerWidth,
            focusedPlaceholderColor:
              cardStyles?.focusedPlaceholderColor ??
              sharedComponentStyles.defaultStyles.focusedPlaceholderColor,
            cardElevation:
              cardStyles?.cardElevation ??
              sharedComponentStyles.defaultStyles.cardElevation,
            fontFamily:
              cardStyles?.fontFamily ??
              sharedComponentStyles.defaultStyles.fontFamily,
            fontWeight:
              cardStyles?.fontWeight ??
              sharedComponentStyles.defaultStyles.fontWeight,
            italic:
              cardStyles?.italic ?? sharedComponentStyles.defaultStyles.italic,
          }}
          {...props}
        />
      </View>
    );
  }
);

const defaultStyles = StyleSheet.create({
  cardDetailsForm: {
    ...Platform.select({
      android: {
        minHeight: 310,
      },
      default: {
        minHeight: 190,
      },
    }),
  },
});
