import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  Signal,
  effect,
  inject,
} from '@angular/core';
import { HomeService } from '../home.service';
import { DataTableComponent } from '../../shared/data-table/data-table.component';
import {
  VisitActionState,
  Controls,
  Site,
  UiCollaborater,
  UiTableVisitItemExpended,
  UiUser,
  UiVisit,
  VisitStatus,
  UiVisitor,
  VisitActionItemPayload,
  PartialUiVisit,
} from 'src/app/core/interfaces/interfaces.ui';
import { BehaviorSubject, Observable, combineLatest, tap } from 'rxjs';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { Router, RouterLink } from '@angular/router';
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { SelectComponent } from '../../shared/reactive-select/select.component';
import { MomentDateModule } from '@angular/material-moment-adapter';
import { ReactiveButtonComponent } from '../../shared/reactive-button/reactive-button.component';
import { LoadingService } from '../../shared/services/loading.service';
import moment from 'moment';
import { FilterFormComponent } from './forms/filter-form.component';
import { CommonModule } from '@angular/common';
import { VisitService } from '../../visit/visit.service';
import { AuthSignalsStateService } from 'src/app/components/shared/services/signal-state/auth-signals-state.service';
import { VisitSignalsStateService } from '../../shared/services/signal-state/visit-signals-state.service';
import {MatTabsModule} from '@angular/material/tabs';

import {
  ITableFetchParams,
  UiPaginatedData,
  UiTableAction,
} from 'src/app/core/interfaces/datatable.interface';
import { DialogService } from '../../shared/services/dialog.service';
import { utilsHelper } from 'src/app/core/utils/helpers/utils.helper';
import { SelectVisitorsComponent } from '../../visitor/forms/select-visitors.component';
import { VisitorService } from '../../visitor/visitor.service';
import { CollaboratorSignalsStateService } from '../../shared/services/signal-state/collaborator-signals-state.service';

@Component({
  selector: 'app-home',
  styleUrls: ['./home.component.scss'],
  standalone: true,
  imports: [
    RouterLink,
    MatCheckboxModule,
    DataTableComponent,
    FormsModule,
    ReactiveFormsModule,
    MatFormFieldModule,
    MatInputModule,
    MatDatepickerModule,
    MomentDateModule,
    SelectComponent,
    ReactiveButtonComponent,
    FilterFormComponent,
    CommonModule,
    MatTabsModule,
  ],
  template: `<div>
    <div class="card-header flex flex-col justify-between">
      <div class="w-full">
        <h1>Visites </h1>
      </div>
      <div class="card mt-6 rounded-2xl p-5 shadow-none">
        <h3 class="text-center">Rechercher et filtrer les visites</h3>

        <app-filter-form class="mb-2" [filterTableGroup]="filterTableGroup" />
        <div class="flex flex-wrap justify-end gap-x-8">
          <reactive-button
            class="p-2"
            [hint]="{ label: 'Mettre à jour les données ci-dessous.', position: 'left' }"
            icon="update"
            variant="primary"
            [disabled]="disableSearch"
            (click)="search()">
            Appliquer les filtres
          </reactive-button>
          <!-- <reactive-button
            class="p-2"
            [hint]="{
              label: 'Télécharger le récapitulatif des visites au format Excel'
            }"
            standalone
            variant="secondary"
            icon="download"
            (click)="downloadExcel()">
          </reactive-button> -->
        </div>
      </div>
    </div>

    <div class="card-content mt-7">
      <mat-tab-group>
        <mat-tab *ngFor="let column of visitColumns; let i = index" label="{{ column }}">
          <ng-template mat-tab-label>{{ column }}</ng-template>
          <app-data-table
            [columnWidths]="['20%', '13%', '12%', '20%', '10%', '10%', '15%', '10%']"
            hidePageSize
            [tableDataFetchMethod]="getVisitesSearchResult.bind(this)"
          ></app-data-table>
        </mat-tab>
      </mat-tab-group>
    </div>




    <div class="mt-5">
      <table cellspacing="5" cellpadding="5" class="border border-gray-200 text-xs">
        <tbody>
        <tr>
          <td colspan="4"><h4>Légende</h4></td>
        </tr>
        <tr>
          <td width="150">
            <span ng-reflect-ng-class="chip-to_confirm" class="chip-to_confirm">A confirmer</span>
          </td>
          <td>Visite programmée en attente de confirmation par le(s) visiteur(s) invité(s)</td>
          <td>
            <span ng-reflect-ng-class="chip-in_progress" class="chip-in_progress">En cours</span>
          </td>
          <td>Visite en cours.</td>
        </tr>
        <tr>
          <td>
              <span ng-reflect-ng-class="chip-initiator_confirm" class="chip-initiator_confirm"
              >Init. en attente</span
              >
          </td>
          <td>
            Visite programmée confirmée par le(s) visiteur(s) invité(s), en attente de
            vérification et validation par l'initiateur de la visite.
          </td>
          <td><span ng-reflect-ng-class="chip-refused" class="chip-refused">Refusée</span></td>
          <td>
            Visite programmée refusée par le(s) visiteur(s) invité(s) ou par l'initiateur de la
            visite.
          </td>
        </tr>
        <tr>
          <td><span ng-reflect-ng-class="chip-planned" class="chip-planned">Programmée</span></td>
          <td>
            Visite programmée confirmée par le(s) visiteur(s) invité(s) et par l'initiateur de la
            visite.
          </td>
          <td><span ng-reflect-ng-class="chip-finish" class="chip-finish">Terminée</span></td>
          <td>Visite terminée.</td>
        </tr>
        </tbody>
      </table>
    </div>
  </div>`,
})
export class HomeComponent {
  showSearchResults = true;
  collabIsLoading: Signal<boolean>;
  currentUser: Signal<UiUser | null>;
  disableSearch = true;
  visitFilters!: Partial<{
    visitDateStart: moment.Moment | null;
    visitDateEnd: moment.Moment | null;
    collaborater?: UiCollaborater | null | undefined;
    site?: Site | null | undefined;
    archive: boolean;
  }>;

  // TODO: move actionState as an interface to implement on component to provide data table component with actions if needed
  actions: VisitActionState = {
    update: (payload: VisitActionItemPayload) =>
      this.updateVisitAction(payload.visit, payload.initial),
    remove: (payload: VisitActionItemPayload) =>
      this.removeVisitAction(payload.visit, payload.initial),
    details: (payload: VisitActionItemPayload) =>
      this.detailsVisitAction(payload.visit, payload.initial),
    checkin: (payload: VisitActionItemPayload) =>
      this.checkinAction(payload.visit, payload.initial),
    checkout: (payload: VisitActionItemPayload) =>
      this.checkoutAction(payload.visit, payload.initial),
    confirm: (payload: VisitActionItemPayload) =>
      this.confirmVisitAction(payload.visit, payload.initial),
    finish: (payload: VisitActionItemPayload) =>
      this.finishVisitAction(payload.visit, payload.initial),
    start: (payload: VisitActionItemPayload) => this.startAction(payload.visit, payload.initial),
  };

  public filterTableGroup: FormGroup;

  public visitColumns = [
    'En cours',
    'A confirmer',
    'En attente',
    'Terminées',
    'Programmées'
  ];

  private loading = inject(LoadingService);
  private router = inject(Router);
  private homeService = inject(HomeService);
  private visitService = inject(VisitService);
  private authState = inject(AuthSignalsStateService);
  private visitState = inject(VisitSignalsStateService);
  private dialogService = inject(DialogService);
  private visitorService = inject(VisitorService);
  private collabState = inject(CollaboratorSignalsStateService);
  private cd = inject(ChangeDetectorRef);

  public isLoading = false;
  constructor() {
    this.collabIsLoading = this.collabState.select('isLoading');
    this.currentUser = this.authState.select('user');

    this.filterTableGroup = new FormGroup<Controls<FilterTableForm>>({
      visitDateStart: new FormControl(null),
      visitDateEnd: new FormControl(null),
      collaborater: new FormControl({ value: null, disabled: this.collabIsLoading() }),
      site: new FormControl(null),
      archive: new FormControl(false),
    });

    effect(() => {
      if (this.collabIsLoading()) {
        this.filterTableGroup.get('collaborater')?.disable();
      } else {
        this.filterTableGroup.get('collaborater')?.enable();
      }
    });
  }

  getVisitesSearchResult = (
    params: ITableFetchParams
  ): Observable<UiPaginatedData<any>> => {
    this.filterTableGroup.valueChanges.subscribe(filters => {
      this.disableSearch = false;
      this.visitFilters = filters;
    });

    const filteredFilters = utilsHelper.filterEntries<typeof this.visitFilters>(this.visitFilters);

    return this.homeService.getTableDataExtended(
      {
        username: filteredFilters?.collaborater?.username,
        startDate: filteredFilters?.visitDateStart?.format('DD/MM/YYYY'),
        endDate: filteredFilters?.visitDateEnd
          ? filteredFilters.visitDateEnd?.format('DD/MM/YYYY')
          : filteredFilters?.visitDateStart?.format('DD/MM/YYYY'),
        site: filteredFilters?.site?.id,
        archive: filteredFilters?.archive,
      },
      this.actions,
      params
    );
  };

  search = () => {
    this.loading.show();
    this.disableSearch = true;
    this.showSearchResults = false;
    setTimeout(() => {
      this.showSearchResults = true;
      this.loading.hide();
    }, 100);
  };

  downloadExcel = () => {
    this.homeService
      .getApiPaginatedVisites({}, { pagination: { pageIndex: 0, pageSize: 1000 } })
      .subscribe(visites => {
        utilsHelper.generateExcel(visites.elements, 'visites');
      });
  };

  removeVisitAction = (
    visit: BehaviorSubject<UiTableVisitItemExpended>,
    initial: PartialUiVisit
  ): UiTableAction => ({
    action: () => {
      this.visitService
        .removeVisit(initial.id as number)
        ?.pipe(
          tap(() => {
            this.search();
          })
        )
        .subscribe();
      this.updateStatusWithActions('finish', visit);
    },
    label: 'Archiver la visite',
    icon: 'cancel',
    hidden: initial.archive || false,
    hint: { label: 'La visite sera historisée' },
  });

  updateVisitAction = (
    visit: BehaviorSubject<UiTableVisitItemExpended>,
    initial?: PartialUiVisit
  ): UiTableAction => ({
    action: () => {
      this.visitState.enableEditMode(initial?.id as string);
      return this.router.navigate(['private/enregistrement'], {
        queryParams: { visitId: initial?.id },
      });
    },
    label: 'Modifier les informations',
    hint: { label: 'Modifier la visite' },
    icon: 'update',
  });

  detailsVisitAction = (
    visit: BehaviorSubject<UiTableVisitItemExpended>,
    initial?: PartialUiVisit
  ): UiTableAction => ({
    hidden: false,
    action: () => {
      this.router.navigate(['private', 'visit', initial?.id]);

      return;
    },
    label: 'Voir le détail',
    icon: 'info',
  });

  confirmVisitAction = (
    visit: BehaviorSubject<UiTableVisitItemExpended>,
    initial?: PartialUiVisit
  ): UiTableAction => ({
    hidden: false,
    action: () => {
      if (initial?.status !== 'initiator_confirmation')
        return this.dialogService.openSimpleReactiveDialogWithoutActions({
          title: 'Erreur',
          message: 'Le statut actuel de la visite ne permet pas une validation de votre part',
        });

      this.visitorService.getVisitorsFromVisit(initial.id as number).subscribe(visitors => {
        this.loading.hide();
        this.dialogService
          .open(SelectVisitorsComponent, {
            data: {
              visitors: visitors.filter(v => !v.response?.refusal && !v.confirmee),
              multiple: false,
              itemAction: (visitor: UiVisitor, ref) => {
                ref.close();
                this.router.navigate(['private', 'final-confirmation', initial?.id, visitor.id]);
              },
            },
            width: '500px',
          })
          .afterClosed()
          .subscribe();
      });
    },
    label: 'Confirmer le(s) visiteur(s)',
    hint: { label: "Confirmer la venue d'un(des) visiteur(s)" },
    icon: 'check_circle',
  });

  checkinAction = (
    visit: BehaviorSubject<UiTableVisitItemExpended>,
    initial: PartialUiVisit
  ): UiTableAction => ({
    action: () => {
      this.loading.show();
      this.visitorService.getVisitorsFromVisit(initial.id as number).subscribe(visitors => {
        this.loading.hide();
        this.dialogService
          .open(SelectVisitorsComponent, {
            data: {
              visitors: visitors.filter(v => !v.response?.refusal && !v.present),
              multiple: true,
            },
            width: '500px',
          })
          .afterClosed()
          .subscribe(selectedVisitors => {
            if (!selectedVisitors) return;
            combineLatest(
              selectedVisitors?.map(visitor =>
                this.visitService.reportPresence({
                  visitId: initial.id as number,
                  visitorId: visitor.id as number,
                })
              )
            ).subscribe(response => {
              if (response.at(-1)?.statusUpdated) {
                this.updateStatusWithActions('in_progress', visit, initial);
              }
            });
          });
      });
    },
    label: 'Signaler une entrée',
    hint: { label: "Signaler l'entrée d'un visiteur et modifier l'état de la visite " },
    icon: 'door_open',
  });

  startAction = (
    visit: BehaviorSubject<UiTableVisitItemExpended>,
    initial: PartialUiVisit
  ): UiTableAction => ({
    action: () => {
      this.loading.show();
      this.visitorService.getVisitorsFromVisit(initial.id as number).subscribe(visitors => {
        this.visitService
          .updateStatus(
            {
              ...initial,
              visitors,
            },
            'in_progress'
          )
          .subscribe(() => {
            this.updateStatusWithActions('in_progress', visit, initial);
            this.loading.hide();
          });
      });
    },
    label: 'Commencer la visite',
    hint: { label: 'Signaler la visite en cours' },
    icon: 'start',
  });

  checkoutAction = (
    visit: BehaviorSubject<UiTableVisitItemExpended>,
    initial: PartialUiVisit
  ): UiTableAction => ({
    action: () => {
      // TODO: open dialog to choose who went out
    },
    icon: 'door_back',
    label: 'Signaler une sortie',
    hidden: true,
    hint: { label: "Signaler la sortie d'un visiteur" },
  });

  finishVisitAction = (
    visit: BehaviorSubject<UiTableVisitItemExpended>,
    initial: PartialUiVisit
  ): UiTableAction => ({
    action: () => {
      this.loading.show();
      this.visitorService.getVisitorsFromVisit(initial.id as number).subscribe(visitors => {
        this.visitService
          .updateStatus(
            {
              ...initial,
              visitors,
              schedule: {
                ...initial.schedule,
                departureDate: utilsHelper.day(),
                departureTime: utilsHelper.getNextHour(true),
              },
            },
            'finish'
          )
          .subscribe(() => {
            this.updateStatusWithActions('finish', visit, initial);
            this.loading.hide();
          });

        console.log({
          schedule: {
            ...initial.schedule,
            departureDate: utilsHelper.day(),
            departureTime: utilsHelper.getNextHour(true),
          },
        });
      });
    },
    icon: 'check_circle',
    label: 'Terminer la visite',
    hint: { label: 'Terminer la visite et modifier le statut' },
  });

  updateStatusWithActions = (
    status: VisitStatus,
    visit: BehaviorSubject<UiTableVisitItemExpended>,
    initial?: PartialUiVisit
  ) => {
    return visit.next({
      ...visit.value,
      status: this.homeService.updateStatusItem(status, 'chip'),
      actions: this.homeService
        .getActionsFromStatus(this.actions, status)
        .map(action => action({ visit, initial: initial as PartialUiVisit })),
    });
  };


}

export type FilterTableForm = FormGroup<{
  visitDateStart: FormControl<moment.Moment | null>;
  visitDateEnd: FormControl<moment.Moment | null>;
  collaborater?: FormControl<UiCollaborater | null>;
  site?: FormControl<Site | null>;
  archive: FormControl<boolean | null>;
}>;