import React, { type JSX } from 'react';
import ElixFormsComponentAbstract from '@common/src/ElixFormsComponentAbstract';
import type { IElixFormsComponentCustomFormFieldFactory } from '@common/src/IElixFormsComponentCustomFormFieldFactory';
import { ElixFormsElement } from '@common/src/ElixFormsElement';
import { QueryParamHelper } from '@common/src/QueryParamHelper';
import config from './config.json';

interface ContrattoResult {
  idContratto: string;
  titoloContratto: string;
  idDomanda: string;
  idRicevuta: string;
}

interface RecuperoPropostaState {
  searchText: string;
  searchResults: ContrattoResult[];
  isLoading: boolean;
  isDropdownOpen: boolean;
  selectedContract: ContrattoResult | null;
  highlightedIndex: number;
  errorMessage: string;
}

export default class RecuperoPropostaCctDaContrattiComponent extends ElixFormsComponentAbstract {
  private autocompleteState: RecuperoPropostaState = {
    searchText: '',
    searchResults: [],
    isLoading: false,
    isDropdownOpen: false,
    selectedContract: null,
    highlightedIndex: -1,
    errorMessage: '',
  };

  private debounceTimer: ReturnType<typeof setTimeout> | null = null;

  private autocompleteRef: React.RefObject<HTMLDivElement | null> = React.createRef();

  private static readonly formFieldKeys = {
    codiceContratto: config.elixForms.outputs.codiceContratto,
    titoloContratto: config.elixForms.outputs.titoloContratto,
    idDomanda: config.elixForms.outputs.idDomanda,
    idRicevuta: config.elixForms.outputs.idRicevuta,
  } as const;

  private codiceFiscale: string;

  constructor(props: any) {
    super(props);
    this.codiceFiscale = QueryParamHelper.getDecodedTextFromQuery(config.elixForms.inputs.codiceFiscale) ?? '';
  }

  override componentDidMount(): void {
    document.addEventListener('mousedown', this.handleClickOutside);
  }

  override componentWillUnmount(): void {
    document.removeEventListener('mousedown', this.handleClickOutside);
    if (this.debounceTimer) {
      clearTimeout(this.debounceTimer);
    }
  }

  private handleClickOutside = (event: MouseEvent): void => {
    if (this.autocompleteRef.current && !this.autocompleteRef.current.contains(event.target as Node)) {
      this.autocompleteState.isDropdownOpen = false;
      this.forceUpdate();
    }
  };

  private async fetchContratti(searchTerm: string): Promise<void> {
    this.autocompleteState.isLoading = true;
    this.autocompleteState.errorMessage = '';
    this.forceUpdate();

    try {
      const url = new URL(config.contrattiWS.apiUrl);
      url.searchParams.set('cod_fis', this.codiceFiscale);
      url.searchParams.set('term', searchTerm);

      const credentials = btoa(`${config.contrattiWS.apiUsername}:${config.contrattiWS.apiPassword}`);

      const response = await fetch(url.toString(), {
        method: 'GET',
        headers: {
          Authorization: `Basic ${credentials}`,
          'X-Api-Key': config.contrattiWS.apiKey,
          Accept: 'application/json',
        },
      });

      if (!response.ok) {
        throw new Error(`Errore API: ${response.status} ${response.statusText}`);
      }

      const data: ContrattoResult[] = await response.json();

      this.autocompleteState.searchResults = data;
      this.autocompleteState.isDropdownOpen = data.length > 0;
      this.autocompleteState.highlightedIndex = -1;
      this.autocompleteState.isLoading = false;
      this.forceUpdate();
    } catch (error) {
      console.error('Errore durante la ricerca contratti:', error);
      this.autocompleteState.searchResults = [];
      this.autocompleteState.isDropdownOpen = false;
      this.autocompleteState.isLoading = false;
      this.autocompleteState.errorMessage = error instanceof Error ? error.message : 'Errore durante la ricerca';
      this.forceUpdate();
    }
  }

  private handleSearchChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
    const text = event.target.value;
    this.autocompleteState.searchText = text;

    if (text.length === 0) {
      this.autocompleteState.searchResults = [];
      this.autocompleteState.isDropdownOpen = false;
      this.autocompleteState.highlightedIndex = -1;
      this.autocompleteState.errorMessage = '';
      this.clearSelection();
      this.forceUpdate();
      return;
    }

    if (this.debounceTimer) {
      clearTimeout(this.debounceTimer);
    }

    if (text.length >= config.component.minCharsForSearch) {
      this.debounceTimer = setTimeout(() => {
        this.fetchContratti(text);
      }, 300);
    } else {
      this.autocompleteState.searchResults = [];
      this.autocompleteState.isDropdownOpen = false;
      this.autocompleteState.highlightedIndex = -1;
      this.forceUpdate();
    }
  };

  private handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>): void => {
    const { searchResults, isDropdownOpen, highlightedIndex } = this.autocompleteState;

    if (!isDropdownOpen || searchResults.length === 0) return;

    switch (event.key) {
      case 'ArrowDown':
        event.preventDefault();
        this.autocompleteState.highlightedIndex = Math.min(highlightedIndex + 1, searchResults.length - 1);
        this.forceUpdate();
        break;

      case 'ArrowUp':
        event.preventDefault();
        this.autocompleteState.highlightedIndex = Math.max(highlightedIndex - 1, 0);
        this.forceUpdate();
        break;

      case 'Enter':
        event.preventDefault();
        if (highlightedIndex >= 0 && highlightedIndex < searchResults.length) {
          this.selectContract(searchResults[highlightedIndex]);
        }
        break;

      case 'Escape':
        event.preventDefault();
        this.autocompleteState.isDropdownOpen = false;
        this.forceUpdate();
        break;
    }
  };

  private selectContract(contract: ContrattoResult): void {
    this.autocompleteState.selectedContract = contract;
    this.autocompleteState.searchText = `[${contract.idContratto}] ${contract.titoloContratto}`;
    this.autocompleteState.isDropdownOpen = false;
    this.autocompleteState.searchResults = [];
    this.autocompleteState.highlightedIndex = -1;

    this.setState({
      formData: {
        ...this.state.formData,
        [RecuperoPropostaCctDaContrattiComponent.formFieldKeys.codiceContratto]: contract.idContratto,
        [RecuperoPropostaCctDaContrattiComponent.formFieldKeys.titoloContratto]: contract.titoloContratto,
        [RecuperoPropostaCctDaContrattiComponent.formFieldKeys.idDomanda]: contract.idDomanda,
        [RecuperoPropostaCctDaContrattiComponent.formFieldKeys.idRicevuta]: contract.idRicevuta,
      },
    });
  }

  private clearSelection(): void {
    this.autocompleteState.selectedContract = null;

    this.setState({
      formData: {
        ...this.state.formData,
        [RecuperoPropostaCctDaContrattiComponent.formFieldKeys.codiceContratto]: '',
        [RecuperoPropostaCctDaContrattiComponent.formFieldKeys.titoloContratto]: '',
        [RecuperoPropostaCctDaContrattiComponent.formFieldKeys.idDomanda]: '',
        [RecuperoPropostaCctDaContrattiComponent.formFieldKeys.idRicevuta]: '',
      },
    });
  }

  private renderAutocomplete(): JSX.Element {
    const { searchResults, isLoading, isDropdownOpen, highlightedIndex, errorMessage, searchText } = this.autocompleteState;

    const autocompleteInput = (
      <>
        <div className="position-relative" ref={this.autocompleteRef}>
          <input
            id="autocomplete-search"
            name="autocomplete-search"
            className="form-control"
            type="text"
            placeholder="Digita almeno 3 caratteri per cercare..."
            value={searchText}
            onChange={this.handleSearchChange}
            onKeyDown={this.handleKeyDown}
            autoComplete="off"
          />

          {isLoading && (
            <div className="autocompleteDropdown mt-2 p-3 text-muted">
              <span className="me-2">
                <span className="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
              </span>
              Ricerca in corso...
            </div>
          )}

          {!isLoading && isDropdownOpen && searchResults.length > 0 && (
            <div className="autocompleteDropdown mt-2">
              {searchResults.map((contract, index) => (
                <div
                  key={`${contract.idContratto}_${index}`}
                  className={`autocompleteItem${index === highlightedIndex ? ' isHighlighted' : ''}`}
                  onMouseDown={(event) => {
                    event.preventDefault();
                    this.selectContract(contract);
                  }}
                  onMouseEnter={() => {
                    this.autocompleteState.highlightedIndex = index;
                    this.forceUpdate();
                  }}
                >
                  <span className="fw-semibold">[{contract.idContratto}]</span>{' '}
                  <span>{contract.titoloContratto}</span>
                </div>
              ))}
            </div>
          )}

          {!isLoading && isDropdownOpen && searchResults.length === 0 && (
            <div className="autocompleteDropdown mt-2 p-3 text-muted">Nessun risultato trovato</div>
          )}

          {errorMessage && (
            <div className="alert alert-danger mt-2">{errorMessage}</div>
          )}
        </div>

        {this.autocompleteState.selectedContract && (
          <div className="card mt-3">
            <div className="card-body">
              <div className="row g-2">
                <div className="col-12 col-md-6"><strong>ID Contratto:</strong> {this.autocompleteState.selectedContract.idContratto}</div>
                <div className="col-12 col-md-6"><strong>Titolo:</strong> {this.autocompleteState.selectedContract.titoloContratto}</div>
                <div className="col-12 col-md-6"><strong>ID Domanda:</strong> {this.autocompleteState.selectedContract.idDomanda}</div>
                <div className="col-12 col-md-6"><strong>ID Ricevuta:</strong> {this.autocompleteState.selectedContract.idRicevuta}</div>
              </div>
            </div>
          </div>
        )}
      </>
    );

    return new ElixFormsElement(
      <label className="form-label fw-semibold" htmlFor="autocomplete-search">Cerca Contratto</label>,
      autocompleteInput
    ).render();
  }

  protected override createCustomFormFields(formFieldFactory: IElixFormsComponentCustomFormFieldFactory): JSX.Element {
    const fieldKeys = RecuperoPropostaCctDaContrattiComponent.formFieldKeys;
    const idContratto = this.state.formData[fieldKeys.codiceContratto] ?? '';
    const titoloContratto = this.state.formData[fieldKeys.titoloContratto] ?? '';
    const idDomanda = this.state.formData[fieldKeys.idDomanda] ?? '';
    const idRicevuta = this.state.formData[fieldKeys.idRicevuta] ?? '';

    return (
      <>
        {this.renderAutocomplete()}
        <input type="hidden" id="idContratto_hidden" name={fieldKeys.codiceContratto} value={idContratto} />
        <input type="hidden" id="titoloContratto_hidden" name={fieldKeys.titoloContratto} value={titoloContratto} />
        <input type="hidden" id="idDomanda_hidden" name={fieldKeys.idDomanda} value={idDomanda} />
        <input type="hidden" id="idRicevuta_hidden" name={fieldKeys.idRicevuta} value={idRicevuta} />
      </>
    );
  }
}
