/*
 * https://github.com/morethanwords/tweb
 * Copyright (C) 2019-2021 Eduard Kuzmenko
 * https://github.com/morethanwords/tweb/blob/master/LICENSE
 */

import PopupElement from '.';
import placeCaretAtEnd from '../../helpers/dom/placeCaretAtEnd';
import {InputInvoice, PaymentRequestedInfo, PaymentsPaymentForm, PaymentsValidatedRequestedInfo} from '../../layer';
import matchEmail from '../../lib/richTextProcessor/matchEmail';
import CheckboxField from '../checkboxField';
import CountryInputField from '../countryInputField';
import InputField from '../inputField';
import Row from '../row';
import SettingSection from '../settingSection';
import TelInputField from '../telInputField';
import {PaymentButton} from './payment';
import {createCountryZipFields, handleInputFieldsOnChange, InputFieldCorrected} from './paymentCard';

export type PaymentShippingAddress = PaymentRequestedInfo;

type ShippingFocusField = 'name' | 'email' | 'phone';

export default class PopupPaymentShipping extends PopupElement<{
  finish: (o: {shippingAddress: PaymentShippingAddress, requestedInfo: PaymentsValidatedRequestedInfo}) => void
}> {
  constructor(
    private paymentForm: PaymentsPaymentForm,
    private inputInvoice: InputInvoice,
    private focus?: ShippingFocusField
  ) {
    super('popup-payment popup-payment-shipping', {
      closable: true,
      overlayClosable: true,
      body: true,
      scrollable: true,
      title: 'PaymentShippingInfo'
    });

    this.d();
  }

  private d() {
    const paymentForm = this.paymentForm;
    const invoice = paymentForm.invoice;
    const savedInfo = this.paymentForm.saved_info;

    let addressSection: SettingSection,
      address1InputField: InputField,
      address2InputField: InputField,
      cityInputField: InputField,
      stateInputField: InputField,
      countryInputField: CountryInputField,
      postcodeInputField: InputFieldCorrected;
    if(invoice.pFlags.shipping_address_requested) {
      addressSection = new SettingSection({name: 'PaymentShippingAddress', noDelimiter: true, noShadow: true});
      address1InputField = new InputField({label: 'PaymentShippingAddress1Placeholder', maxLength: 64, required: true});
      address2InputField = new InputField({label: 'PaymentShippingAddress2Placeholder', maxLength: 64});
      cityInputField = new InputField({label: 'PaymentShippingCityPlaceholder', maxLength: 64, required: true});
      stateInputField = new InputField({label: 'PaymentShippingStatePlaceholder', maxLength: 64});
      const res = createCountryZipFields(true, true);
      countryInputField = res.countryInputField;
      postcodeInputField = res.postcodeInputField;

      addressSection.content.append(...[
        address1InputField,
        address2InputField,
        cityInputField,
        stateInputField,
        countryInputField,
        postcodeInputField
      ].filter(Boolean).map((inputField) => inputField.container));
    }

    let receiverSection: SettingSection;
    let nameInputField: InputField, emailInputField: InputField, telInputField: TelInputField;
    if([invoice.pFlags.name_requested, invoice.pFlags.email_requested, invoice.pFlags.phone_requested].includes(true)) {
      receiverSection = new SettingSection({name: 'PaymentShippingReceiver', noDelimiter: true, noShadow: true});

      const validateEmail = () => {
        const value = emailInputField.value;
        const match = matchEmail(value);
        if(!match || match[0].length !== value.length) {
          return false;
        }

        return true;
      };

      const validatePhone = () => {
        return !!telInputField.value.match(/\d/);
      };

      if(invoice.pFlags.name_requested) nameInputField = new InputField({label: 'PaymentShippingName', maxLength: 256, required: true});
      if(invoice.pFlags.email_requested) emailInputField = new InputField({label: 'PaymentShippingEmailPlaceholder', maxLength: 64, required: true, validate: validateEmail});
      if(invoice.pFlags.phone_requested) telInputField = new TelInputField({required: true, validate: validatePhone});

      receiverSection.content.append(...[
        nameInputField,
        emailInputField,
        telInputField
      ].filter(Boolean).map((inputField) => inputField.container));
    }

    const saveCheckboxField = new CheckboxField({
      text: 'PaymentShippingSave',
      checked: true
    });
    const saveRow = new Row({
      checkboxField: saveCheckboxField,
      subtitleLangKey: 'PaymentShippingSaveInfo'
    });

    (receiverSection || addressSection).content.append(saveRow.container);

    this.scrollable.append(...[addressSection, receiverSection].filter(Boolean).map((section) => section.container));

    const payButton = PaymentButton({
      key: 'PaymentInfo.Done',
      onClick: async() => {
        const selectedCountry = countryInputField && countryInputField.getSelected().country;
        const data: PaymentShippingAddress = {
          _: 'paymentRequestedInfo',
          shipping_address: selectedCountry && {
            _: 'postAddress',
            street_line1: address1InputField.value,
            street_line2: address2InputField.value,
            city: cityInputField.value,
            state: stateInputField.value,
            // country: countryInputField.value,
            country_iso2: selectedCountry?.iso2,
            post_code: postcodeInputField.value
          },
          name: nameInputField?.value,
          email: emailInputField?.value,
          phone: telInputField?.value
        };

        try {
          const requestedInfo = await this.managers.appPaymentsManager.validateRequestedInfo(this.inputInvoice, data, saveCheckboxField?.checked);

          this.dispatchEvent('finish', {
            shippingAddress: data,
            requestedInfo
          });

          this.hide();
        } catch(err: any) {
          const errorMap: {[err: string]: InputField} = {
            ADDRESS_STREET_LINE1_INVALID: address1InputField,
            ADDRESS_STREET_LINE2_INVALID: address2InputField,
            ADDRESS_COUNTRY_INVALID: countryInputField,
            ADDRESS_CITY_INVALID: cityInputField,
            ADDRESS_STATE_INVALID: stateInputField,
            ADDRESS_POSTCODE_INVALID: postcodeInputField,

            REQ_INFO_NAME_INVALID: nameInputField,
            REQ_INFO_EMAIL_INVALID: emailInputField,
            REQ_INFO_PHONE_INVALID: telInputField
          };

          const inputField = errorMap[(err as ApiError).type];
          if(inputField) {
            inputField.setError();
            (err as any).handled = true;
          }

          throw err;
        }
      }
    });
    this.body.append(this.btnConfirmOnEnter = payButton);

    if(savedInfo) {
      const shippingAddress = savedInfo.shipping_address;
      if(shippingAddress) {
        address1InputField.value = shippingAddress.street_line1;
        address2InputField.value = shippingAddress.street_line2;
        cityInputField.value = shippingAddress.city;
        stateInputField.value = shippingAddress.state;
        countryInputField.selectCountryByIso2(shippingAddress.country_iso2);
        postcodeInputField.value = shippingAddress.post_code;
      }

      savedInfo.name && nameInputField && (nameInputField.value = savedInfo.name);
      savedInfo.email && emailInputField && (emailInputField.value = savedInfo.email);
      savedInfo.phone && telInputField && (telInputField.value = savedInfo.phone);
    }

    const {validate} = handleInputFieldsOnChange([
      address1InputField,
      address2InputField,
      cityInputField,
      stateInputField,
      countryInputField,
      postcodeInputField,
      nameInputField,
      emailInputField,
      telInputField
    ].filter(Boolean), (valid) => {
      payButton.disabled = !valid;
    });

    validate();

    this.show();

    let focusField: InputField;
    if(this.focus) {
      const focusMap: {[field in ShippingFocusField]?: InputField} = {
        name: nameInputField,
        email: emailInputField,
        phone: telInputField
      };

      focusField = focusMap[this.focus];
    } else {
      focusField = address1InputField;
    }

    if(focusField) {
      placeCaretAtEnd(focusField.input);
    }
  }
}
