import './App.css';

import type { IElixFormsComponentFormState } from './IElixFormsComponentFormState';
import type { IElixFormsComponentProperties } from './IElixFormsComponentProperties';
import type { IElixFormsComponentCustomFormFieldFactory } from './IElixFormsComponentCustomFormFieldFactory';
import type { ElixFormsCheckboxOption, ElixFormsDropdownOption, ElixFormsRadioOption } from './ElixFormsTypes';
import { ElixFormsElement } from './ElixFormsElement';
import { QueryParamHelper } from './QueryParamHelper';
import { Component, type JSX } from 'react';
import React from 'react';

export default abstract class ElixFormsComponentAbstract extends Component<IElixFormsComponentProperties, IElixFormsComponentFormState> {
  constructor(props: IElixFormsComponentProperties) {
    super(props);

    this.state = {
      formData: {}
    };
  }

  private checkboxValues = new Map<string, number[]>();

  private mandatoryFormFieldNames: string[] = [
    'RWE2_MODULE_ID',
    'RWE2_REQUEST_ID',
    'custom-workflow-back-url',
    'custom-workflow-generic-id',
    'custom-workflow-current-tabrel-genid',
    'custom-workflow-source-field',
    'crc',
    'MODULE_TESTMODE_KEY',
    'ELANG'
  ];

  private createMandatoryFormFields(queryParams: URLSearchParams): JSX.Element {
    const hiddenInputs: JSX.Element[] = [];

    this.mandatoryFormFieldNames.forEach(paramName => {
      hiddenInputs.push(this.createHiddenInput(paramName));
    });

    return <>{hiddenInputs}</>;
  }

  private createAdditionalFormFields(): React.ReactElement {
    const schema = JSON.parse(this.props.additionalFieldsJson || '[]');

    return (
      <>
        {schema.map((field: { key: React.Key | null | undefined; }) => (
          <div key={field.key}>
            {this.renderField(field)}
          </div>
        ))}
      </>
    );
  }

  protected createCustomFormFields(formFieldFactory: IElixFormsComponentCustomFormFieldFactory): JSX.Element {
    return <></>;
  }

  private renderCustomFormFields(): JSX.Element {
    const formFieldFactory = {
      createBooleanInput: (name: string, label: string, required: boolean = false) =>
        this.createBooleanInput(name, label, required),
      createCheckboxInput: (name: string, label: string, options: Array<ElixFormsCheckboxOption>) =>
        this.createCheckboxInput(name, label, options),
      createDropdownInput: (name: string, label: string, options: Array<ElixFormsDropdownOption>, required: boolean = false) =>
        this.createDropdownInput(name, label, options, required),
      createHiddenInput: (name: string) =>
        this.createHiddenInput(name),
      createNumberInput: (name: string, label: string, required: boolean = false) =>
        this.createNumberInput(name, label, required),
      createRadioInput: (name: string, label: string, options: Array<ElixFormsRadioOption>, required: boolean = false) =>
        this.createRadioInput(name, label, options, required),
      createTextInput: (name: string, label: string, required: boolean = false) =>
        this.createTextInput(name, label, required),
      createTextAreaInput: (name: string, label: string, required: boolean = false) =>
        this.createTextAreaInput(name, label, required),
    };

    return this.createCustomFormFields(formFieldFactory);
  }

  protected renderExtraContentPre(): JSX.Element | null {
    return null;
  }

  protected renderExtraContentPost(): JSX.Element | null {
    return null;
  }

  public override render(): React.ReactElement<IElixFormsComponentProperties> {
    const {
      isDarkTheme,
      userDisplayName,
      moduleName,
      headerTitle,
      headerHeroImageSrc: headerTitleImageSrc,
      cardTitle,
      cardDescription,
      alertInfoTitle,
      alertInfoMessage,
      instructionsTitle,
      instructionsMessage,
      submitText,
    } = this.props;

    const queryParams = new URLSearchParams(window.location.search);
    const missingMandatoryParams = this.mandatoryFormFieldNames.filter(paramName => !queryParams.has(paramName));
    const hasAuthenticationError = missingMandatoryParams.length > 0;

    return (
      <div>
        <header className="it-header-wrapper text-white">
          {userDisplayName &&
          <div className="it-header-slim-wrapper">
            <div className="container">
              <div className="row">
                <div className="col-12">
                  <div className="it-header-slim-wrapper-content">
                    {/* <a className="d-none d-lg-block navbar-brand" href="#">Ente appartenenza</a> */}
                    <div className="nav-mobile">
                      {/* <nav aria-label="Navigazione accessoria">
                        <a className="it-opener d-lg-none" data-bs-toggle="collapse" href="#menu1a" role="button"
                          aria-expanded="false" aria-controls="menu4">
                          <span>Ente appartenenza</span>
                          <svg className="icon" aria-hidden="true">
                            <use href="/bootstrap-italia/dist/svg/sprites.svg#it-expand"></use>
                          </svg>
                        </a>
                        <div className="link-list-wrapper collapse" id="menu1a">
                          <ul className="link-list">
                            <li><a className="dropdown-item list-item" href="#">Link 1</a></li>
                            <li><a className="list-item active" href="#" aria-current="page">Link 2 (Attivo)</a></li>
                          </ul>
                        </div>
                      </nav> */}
                    </div>
                    <div className="it-header-slim-right-zone">
                      {/* <div className="nav-item dropdown">
                        <a className="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown"
                          aria-expanded="false">
                          <span className="visually-hidden">Selezione lingua: lingua selezionata</span>
                          <span>ITA</span>
                          <svg className="icon d-none d-lg-block">
                            <use href="/bootstrap-italia/dist/svg/sprites.svg#it-expand"></use>
                          </svg>
                        </a>
                        <div className="dropdown-menu">
                          <div className="row">
                            <div className="col-12">
                              <div className="link-list-wrapper">
                                <ul className="link-list">
                                  <li><a className="dropdown-item list-item" href="#"><span>ITA <span
                                          className="visually-hidden">selezionata</span></span></a></li>
                                  <li><a className="dropdown-item list-item" href="#"><span>ENG</span></a></li>
                                </ul>
                              </div>
                            </div>
                          </div>
                        </div>
                      </div> */}
                      <div className="it-access-top-wrapper">
                        {userDisplayName}
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>}

          <div className="it-header-center-wrapper">
            <div className="container">
              <div className="it-header-center-content-wrapper">
                <div className="it-brand-wrapper">
                  <a href="https://www.unipr.it/" title="Torna alla homepage dell'Università di Parma">
                    <img className='icon' src="https://procedure.unipr.it/UploadImgs/12_marchio_UNIPR_neg_b1_squareLogo.png" alt="Università di Parma" />
                    <div className="it-brand-text">
                      <p className="h2 no_toc">Università di Parma</p>
                      {/* <p className="h3 no_toc d-none d-md-block">Procedure Online</p> */}
                    </div>
                  </a>
                </div>

                <div className="it-right-zone">
                  {/* <div className="it-search-wrapper">
                    <span className="d-none d-md-block">Cerca</span>
                    <button className="search-link" aria-label="Cerca">
                      <span className="it-search"></span>
                    </button>
                  </div> */}
                </div>

              </div>
            </div>
          </div>
        </header>

        <div className="container my-2 mx-4">
          <div className='cmp-breadcrumb' role='navigation'>
            <nav className="breadcrumb-container" aria-label="breadcrumb">
              <ol className="breadcrumb">
                <li className='breadcrumb-item'>Procedure Online<span className="separator">&gt;</span></li>
                <li className="breadcrumb-item active" aria-current="page">{moduleName}</li>
              </ol>
            </nav>
          </div>

          {headerTitleImageSrc && <img src={headerTitleImageSrc} alt="Hero Image" className="hero-image img-fluid mb-3" />}
          {headerTitle && (<p className='h2'>{headerTitle}</p>)}

          <div className="container">
            <div className="card shadow-sm mb-4">
              <div className="card-body">
                {cardTitle && <p className="h3 mb-3">{cardTitle}</p>}
                {cardDescription && <p className="lead text-secondary">{cardDescription}</p>}

                {(alertInfoTitle || alertInfoMessage) &&
                  <div className="custom-alert custom-alert-warning" role="status">
                    {alertInfoTitle && <div><b>{alertInfoTitle}</b></div>}
                    {alertInfoMessage && <div className='small'>{alertInfoMessage}</div>}
                  </div>}

                {hasAuthenticationError ? (
                  <div className="alert alert-danger" role="alert">Accesso non autorizzato!</div>
                ) : (
                  <>
                    {this.renderExtraContentPre()}

                    {(instructionsTitle || instructionsMessage) &&
                      <div className="custom-alert custom-alert-info" role="status">
                        {instructionsTitle && <div><b>{instructionsTitle}</b></div>}
                        {instructionsMessage && <div className='small'>{instructionsMessage}</div>}
                      </div>
                    }
                      <form action="https://procedure.unipr.it/rwe2/ComeBackToElixAndSave" method="post" acceptCharset="ISO-8859-1" className="mt-3">
                        {this.createMandatoryFormFields(queryParams)}
                        {this.createAdditionalFormFields()}
                        {this.renderCustomFormFields()}
                        <div className="mt-4 d-flex justify-content-end">
                          <button type="submit" className="btn btn-primary">{submitText ?? 'INVIA'} <span className="it-arrow-right text-white ms-2"></span></button>
                        </div>
                      </form>
                      {this.renderExtraContentPost()}
                    </>
                  )}
              </div>
            </div>
          </div>
        </div>

        <footer className="it-footer text-white">
          <div className="it-footer-small-prints clearfix">
            <div className="container">
              <section>
                <div className="row clearfix">
                  <div className="col-sm-12">
                    <div className="footer-content text-center p-2">
                      <div className="subfooter-top">powered by <span className="highlight">elixForms</span></div>
                      {/* <div className="subfooter-bottom"><div>versione 1.24.0</div></div> */}
                    </div>
                  </div>
                </div>
              </section>
            </div>
          </div>
        </footer>
      </div>
    );
  }

  private createCheckboxInput(paramName: string, label: string, values: Array<ElixFormsCheckboxOption>): JSX.Element {
    const checkedValues = QueryParamHelper.getCheckedFromQuery(paramName);

    if (!this.checkboxValues.get(paramName)) {
      this.checkboxValues.set(paramName, checkedValues);
    }

    const currentValue = this.state.formData[paramName] !== undefined
      ? this.state.formData[paramName]
      : (this.checkboxValues.get(paramName)?.join(',').trim() ?? '');

    const selectedValues = (currentValue || '').split(',').filter(Boolean).map((value: string) => Number(value));

    return new ElixFormsElement(
      <label className="form-label fw-semibold" htmlFor={paramName}>{label}</label>,
      <>
        <div className="d-flex flex-column gap-2" role="group" aria-label={label}>
          {values.map((entry, entryIndex) => {
            const id = `${paramName}_${entryIndex}`;
            const isChecked = selectedValues.includes(entryIndex);

            return (
              <div className="form-check" key={id}>
                <input
                  id={id}
                  className="form-check-input"
                  type="checkbox"
                  checked={isChecked}
                  onChange={(event) => {
                    const currentCheckboxValues = this.checkboxValues.get(paramName) ?? [];
                    const checkboxIndex = currentCheckboxValues.indexOf(entryIndex);
                    const nextValues = [...currentCheckboxValues];

                    if (event.target.checked && checkboxIndex === -1) {
                      nextValues.push(entryIndex);
                    } else if (!event.target.checked && checkboxIndex !== -1) {
                      nextValues.splice(checkboxIndex, 1);
                    }

                    this.checkboxValues.set(paramName, nextValues);
                    const newValue = nextValues.join(',').trim();
                    this.setState({ formData: { ...this.state.formData, [paramName]: newValue } });
                  }}
                />
                <label className="form-check-label" htmlFor={id}>{entry.label}</label>
              </div>
            );
          })}
        </div>
        <input type="hidden" id={paramName} name={paramName} value={currentValue} />
      </>
    ).render();
  }

  private createRadioInput(paramName: string, label: string, values: Array<ElixFormsRadioOption>, required: boolean = false): JSX.Element {
    const currentValue = this.state.formData[paramName] !== undefined
      ? String(this.state.formData[paramName])
      : String(QueryParamHelper.getOptionFromQuery(paramName) ?? '');

    return new ElixFormsElement(
      <span className="form-label fw-semibold">{label}</span>,
      <div className="d-flex flex-column gap-2" role="radiogroup" aria-label={label}>
        {values.map((entry) => {
          const id = `${paramName}_${entry.value}`;
          return (
            <div className="form-check" key={id}>
              <input
                id={id}
                className="form-check-input"
                type="radio"
                name={paramName}
                value={entry.value}
                checked={currentValue === String(entry.value)}
                onChange={() => {
                  this.setState({ formData: { ...this.state.formData, [paramName]: String(entry.value) } });
                }}
                required={required}
              />
              <label className="form-check-label" htmlFor={id}>{entry.label}</label>
            </div>
          );
        })}
      </div>
    ).render();
  }

  private createBooleanInput(paramName: string, label: string, required: boolean = false): JSX.Element {
    const currentValue = this.state.formData[paramName] !== undefined
      ? String(this.state.formData[paramName])
      : String(QueryParamHelper.getOptionFromQuery(paramName) ?? '');

    return new ElixFormsElement(
      <span className="form-label fw-semibold">{label}</span>,
      <div className="d-flex flex-column gap-2" role="radiogroup" aria-label={label}>
        {[{ value: 'true', label: 'Sì' }, { value: 'false', label: 'No' }].map((val) => {
          const id = `${paramName}_${val.value}`;
          return (
            <div className="form-check" key={id}>
              <input
                id={id}
                className="form-check-input"
                type="radio"
                name={paramName}
                value={val.value}
                checked={currentValue === val.value}
                onChange={() => {
                  this.setState({ formData: { ...this.state.formData, [paramName]: val.value } });
                }}
                required={required}
              />
              <label className="form-check-label" htmlFor={id}>{val.label}</label>
            </div>
          );
        })}
      </div>
    ).render();
  }

  private createTextAreaInput(paramName: string, label: string, required: boolean = false): JSX.Element {
    const currentValue = this.state.formData[paramName] !== undefined
      ? String(this.state.formData[paramName])
      : (QueryParamHelper.getDecodedTextFromQuery(paramName) ?? '');

    return new ElixFormsElement(
      <label className="form-label fw-semibold" htmlFor={paramName}>{label}</label>,
      <textarea
        id={paramName}
        name={paramName}
        className="form-control"
        rows={4}
        required={required}
        value={currentValue}
        onChange={(event) => {
          this.setState({ formData: { ...this.state.formData, [paramName]: event.target.value } });
        }}
      />
    ).render();
  }

  private createTextInput(paramName: string, label: string, required: boolean = false): JSX.Element {
    const currentValue = this.state.formData[paramName] !== undefined
      ? String(this.state.formData[paramName])
      : (QueryParamHelper.getDecodedTextFromQuery(paramName) ?? '');

    return new ElixFormsElement(
      <label className="form-label fw-semibold" htmlFor={paramName}>{label}</label>,
      <input
        id={paramName}
        name={paramName}
        className="form-control"
        type="text"
        required={required}
        value={currentValue}
        onChange={(event) => {
          this.setState({ formData: { ...this.state.formData, [paramName]: event.target.value } });
        }}
      />
    ).render();
  }

  private createHiddenInput(paramName: string): JSX.Element {
    const textValue = QueryParamHelper.getDecodedTextFromQuery(paramName) ?? '';
    return <input type="hidden" id={`${paramName}_hidden`} name={paramName} value={textValue} />;
  }

  private createNumberInput(paramName: string, label: string, required: boolean = false): JSX.Element {
    const currentValue = this.state.formData[paramName] !== undefined
      ? String(this.state.formData[paramName])
      : (QueryParamHelper.getDecodedTextFromQuery(paramName) ?? '');

    return new ElixFormsElement(
      <label className="form-label fw-semibold" htmlFor={paramName}>{label}</label>,
      <input
        id={paramName}
        name={paramName}
        className="form-control"
        type="number"
        required={required}
        value={currentValue}
        onChange={(event) => {
          this.setState({ formData: { ...this.state.formData, [paramName]: event.target.value } });
        }}
      />
    ).render();
  }

  private createDropdownInput(paramName: string, label: string, values: Array<ElixFormsDropdownOption>, required: boolean = false): JSX.Element {
    const queryValue = QueryParamHelper.getOptionFromQuery(paramName);
    const currentValue = this.state.formData[paramName] !== undefined
      ? String(this.state.formData[paramName])
      : (queryValue?.toString() ?? '');

    return new ElixFormsElement(
      <label className="form-label fw-semibold" htmlFor={paramName}>{label}</label>,
      <select
        id={paramName}
        name={paramName}
        className="form-select"
        required={required}
        value={currentValue}
        onChange={(event) => {
          this.setState({ formData: { ...this.state.formData, [paramName]: event.target.value } });
        }}
      >
        <option value="">Seleziona...</option>
        {values.map(entry => (
          <option key={entry.value} value={entry.value}>{entry.label}</option>
        ))}
      </select>
    ).render();
  }

  private renderField(field: any): JSX.Element {
    switch (field.type) {
      case 'text':
        return this.createTextInput(field.key, field.label, field.required ?? false);

      case 'textarea':
        return this.createTextAreaInput(field.key, field.label, field.required ?? false);

      case 'radio':
        return this.createRadioInput(field.key, field.label,
          field.options.map((o: any) => ({ value: o.value, label: o.label })),
          field.required ?? false);

      case 'boolean':
        return this.createBooleanInput(field.key, field.label, field.required ?? false);

      case 'checkbox':
        return this.createCheckboxInput(field.key, field.label,
          field.options.map((o: any) => ({ value: o.value, label: o.label, required: o.required ?? false })));

      case 'number':
        return this.createNumberInput(field.key, field.label, field.required ?? false);

      case 'dropdown':
        return this.createDropdownInput(field.key, field.label,
          field.options.map((o: any) => ({ value: o.value, label: o.label })),
          field.required ?? false);

      default:
        return <></>;
    }
  }
}