import { CommonModule } from '@angular/common';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { RxState } from '@rx-angular/state';
import { ConfirmationService, ToastMessageOptions } from 'primeng/api';
import { ButtonModule } from 'primeng/button';
import { CalendarModule } from 'primeng/calendar';
import { ConfirmDialogModule } from 'primeng/confirmdialog';
import { DialogModule } from 'primeng/dialog';
import { DividerModule } from 'primeng/divider';
import { DropdownModule } from 'primeng/dropdown';
import { DialogService } from 'primeng/dynamicdialog';
import { InputNumberModule } from 'primeng/inputnumber';
import { InputTextModule } from 'primeng/inputtext';
import { MessagesModule } from 'primeng/messages';
import { MultiSelectModule } from 'primeng/multiselect';
import { SelectModule } from 'primeng/select';
import { SkeletonModule } from 'primeng/skeleton';
import { TableModule } from 'primeng/table';
import { TabViewModule } from 'primeng/tabview';
import { ToastModule } from 'primeng/toast';
import { ToggleButtonModule } from 'primeng/togglebutton';
import { TooltipModule } from 'primeng/tooltip';
import {
  catchError,
  EMPTY,
  endWith,
  map,
  Observable,
  of,
  startWith,
  switchMap,
  tap,
} from 'rxjs';
import { FiltroExcerptRes } from '../../../../../api/models';
import { MyDirectiveModule } from '../../../../core/directives/my-directive.module';
import { TableColumn } from '../../../../core/models';
import { CruscottiService } from '../../../main/cruscotti/cruscotti.service';

export interface ManageModelComponentState {
  isLoading: boolean;
  showSaveModelDialog: boolean;
  nomeModello: string;
  showViewModelDialog: boolean;
  nomeModelloIsSubmitted: boolean;
  modelloIsSaving: boolean;
  modelValue: any;
  misure: string[];
  ambiente: string;
  transformedValues: { value: string; order: boolean; label: string }[];
  filtri: FiltroExcerptRes[];
  filtriAreLoading: boolean;
  filtriTotalCount: number;
  modelloIsApplying: boolean;
  isSaving: boolean;
  modelloIsDeleting: boolean;
  cdIsLoading: boolean;
}
type State = ManageModelComponentState;

@Component({
  selector: 'app-manage-model',
  imports: [
    CommonModule,
    TableModule,
    InputTextModule,
    SkeletonModule,
    ButtonModule,
    TooltipModule,
    FormsModule,
    ReactiveFormsModule,
    MultiSelectModule,
    CalendarModule,
    DropdownModule,
    ConfirmDialogModule,
    TabViewModule,
    MyDirectiveModule,
    DividerModule,
    SelectModule,
    InputNumberModule,
    DialogModule,
    MessagesModule,
    ToggleButtonModule,
    ToastModule,
  ],
  templateUrl: './manage-model.component.html',
  styleUrl: './manage-model.component.scss',
  providers: [RxState, DialogService, ConfirmationService],
})
export class ManageModelComponent {
  messages: ToastMessageOptions[] = [];
  model$: Observable<ManageModelComponentState>;
  dialogMessages: ToastMessageOptions[] = [];
  buttonMessages: ToastMessageOptions[] = [];

  emptyFiltri: FiltroExcerptRes = {
    id: 0,

    json: '',

    nome: '',

    ts: '',
  };

  emptyFiltriArray = Array(10).fill(this.emptyFiltri);

  cols: TableColumn[] = [
    {
      header: 'Nome',
      field: 'nome',
      sortField: 'nome',
    },
    {
      header: 'Ultima modifica',
      field: 'ts',
      sortField: 'ts',
    },
    {
      header: 'Azioni',
      field: 'azioni',
    },
  ];

  showTransitionOptions = '500ms';

  @Input() set modelValue(modelValue: any) {
    this.state.set({
      modelValue: modelValue,
    });
  }

  @Input() set ambiente(ambiente: string) {
    this.state.set({
      ambiente: ambiente,
    });
  }

  @Input() set misure(misure: string[]) {
    this.state.set({
      misure: misure,
    });
  }

  @Input() set transformedValues(
    transformedValues: { value: string; order: boolean; label: string }[],
  ) {
    this.state.set({
      transformedValues: transformedValues,
    });
  }

  @Output() resJson: EventEmitter<string> = new EventEmitter();

  constructor(
    public state: RxState<State>,
    private cruscottiService: CruscottiService,
    private confirmationService: ConfirmationService,
  ) {
    this.model$ = this.state.select();
    this.state.set({
      isLoading: false,
      showSaveModelDialog: false,
      nomeModello: '',
      showViewModelDialog: false,
      nomeModelloIsSubmitted: false,
      modelloIsSaving: false,
      modelValue: '',
      ambiente: '',
      transformedValues: [],
      filtri: [],
      misure: [],
      filtriAreLoading: false,
      filtriTotalCount: 0,
      modelloIsApplying: false,
      isSaving: false,
      modelloIsDeleting: false,
      cdIsLoading: false,
    });
  }

  getFiltriByAmbiente(ambiente: string) {
    const fetchFiltriByAmbiente$ = of(EMPTY).pipe(
      switchMap(() =>
        this.cruscottiService.getFiltriByAmbiente(ambiente).pipe(
          map((res) => ({
            filtri: res,
            filtriTotalCount: res.length,
          })),
          tap(() => {
            this.state.set({
              showViewModelDialog: true,
            });
          }),
          startWith({ filtriAreLoading: true }),
          endWith({ filtriAreLoading: false }),
        ),
      ),
    );
    this.state.connect(fetchFiltriByAmbiente$);
  }

  createModello() {
    this.state.set({ nomeModelloIsSubmitted: true });
    if (!this.state.get('nomeModello')) {
      return;
    }
    const modelValue = this.state.get('modelValue');
    const misure = this.state.get('misure');
    const polishedParams = {
      nome: this.state.get('nomeModello'),
      json: JSON.stringify({
        ...modelValue,
        misure,
        ordinamento: this.state.get('transformedValues'),
      }),
    };
    const saveAddModello$ = this.cruscottiService
      .createFiltroByAmbiente(this.state.get('ambiente'), polishedParams)
      .pipe(
        catchError((err) => {
          if (err.error.statusCode === 400) {
            this.dialogMessages = [
              {
                severity: 'error',
                life: 5000,
                summary: 'Attenzione!',
                detail: 'Questo nome è già utilizzato',
              },
            ];
          } else {
            this.dialogMessages = [
              {
                severity: 'error',
                life: 5000,
                summary: 'Attenzione!',
                detail: 'Qualcosa è andato storto, riprovare più.',
              },
            ];
          }
          return of(null);
        }),
        tap((res) => {
          if (!res) return;
          this.buttonMessages = [
            {
              severity: 'success',
              summary: 'Operazione completata!',
              life: 5000,
              detail: 'Modello creato con successo',
            },
          ];
          this.state.set(() => ({
            prestazioniRimborsiFormSubmitted: false,
            nomeModelloIsSubmitted: false,
          }));
          this.closeSaveModelDialog();
        }),
        map(() => ({})),
        startWith({ modelloIsSaving: true }),
        endWith({ modelloIsSaving: false }),
      );
    this.state.connect(saveAddModello$);
  }

  sovrascriviModello(event: Event, idModello: number) {
    const modelValue = this.state.get('modelValue');
    const ordinamento = this.state.get('transformedValues');
    const misure = this.state.get('misure');

    const polishedParams = {
      json: JSON.stringify({
        ...modelValue,
        misure,
        ordinamento,
      }),
    };
    this.confirmationService.confirm({
      target: event.target as EventTarget,
      key: 'cd',
      header: 'Sovrascrivi modello',
      icon: 'pi pi-exclamation-triangle',
      message:
        'Questo modello verrà sostituito con i filtri selezionati in questo momento, procedere?',
      acceptLabel: 'Sì, sovrascrivi',
      //acceptButtonStyleClass: 'p-button-danger',
      acceptIcon: 'pi pi-check',
      rejectLabel: 'Annulla',
      accept: () => {
        const saveEditModello$ = this.cruscottiService
          .editFiltroByAmbiente(idModello, polishedParams)
          .pipe(
            catchError(() => {
              this.dialogMessages = [
                {
                  severity: 'error',
                  summary: 'Qualcosa è andato storto!',
                  life: 5000,
                  detail:
                    'Impossibile sovrascrivere il modello al momento, riprova più tardi',
                },
              ];
              return of(null);
            }),
            tap((res) => {
              if (!res) return;
              this.dialogMessages = [
                {
                  severity: 'success',
                  summary: 'Operazione completata!',
                  life: 5000,
                  detail: 'Modello sovrascritto con successo',
                },
              ];
              this.getFiltriByAmbiente(this.state.get('ambiente'));
            }),
            map(() => ({})),
            startWith({ isSaving: true }),
            endWith({ isSaving: false }),
          );
        this.state.connect(saveEditModello$);
      },
    });
  }

  showDeleteModelloDialog(event: Event, idModello: number): void {
    this.confirmationService.confirm({
      target: event.target as EventTarget,
      key: 'cd',
      header: 'Elimina modello',
      icon: 'pi pi-exclamation-triangle',
      message: 'Sei sicuro di voler eliminare questo modello?',
      acceptLabel: 'Sì, elimina',
      acceptButtonStyleClass: 'p-button-danger',
      acceptIcon: 'pi pi-trash',
      rejectLabel: 'Annulla',
      accept: () => {
        const deleteModello$ = this.cruscottiService
          .deleteFiltro(idModello)
          .pipe(
            catchError(() => {
              this.messages = [
                {
                  severity: 'error',
                  life: 5000,
                  summary: 'Attenzione!',
                  detail:
                    'Impossibile eliminare il modello al momento, riprova più tardi',
                },
              ];
              return of(null);
            }),
            tap((res) => {
              if (!res) return;
              this.dialogMessages = [
                {
                  severity: 'success',
                  summary: 'Operazione completata!',
                  life: 5000,
                  detail: 'Modello eliminato con successo',
                },
              ];
              this.getFiltriByAmbiente(this.state.get('ambiente'));
            }),
            map(() => ({})),
            startWith({ modelloIsDeleting: true }),
            endWith({ modelloIsDeleting: false }),
          );
        this.state.connect(deleteModello$);
      },
    });
  }

  applicaModello(idFiltro: number) {
    const saveApplicaModello$ = this.cruscottiService
      .getFiltroById(idFiltro)
      .pipe(
        catchError(() => {
          this.dialogMessages = [
            {
              severity: 'error',
              life: 5000,
              summary: 'Attenzione!',
              detail: 'Qualcosa è andato storto, riprovare più.',
            },
          ];
          return of(null);
        }),
        tap((res) => {
          if (!res) return;
          this.resJson.emit(res.json);
          this.closeUpdateModelDialog();
        }),
        map(() => ({})),
      );
    this.state.connect(saveApplicaModello$);
  }

  openSaveModelDialog() {
    this.state.set({
      showSaveModelDialog: true,
    });
  }

  openViewModelliDialog() {
    this.getFiltriByAmbiente(this.state.get('ambiente'));
  }

  closeSaveModelDialog() {
    this.state.set({
      showSaveModelDialog: false,
      nomeModello: '',
      nomeModelloIsSubmitted: false,
    });
  }

  closeUpdateModelDialog() {
    this.state.set({
      showViewModelDialog: false,
    });
  }
}
