import {Component, computed, inject, OnDestroy, OnInit, signal} from '@angular/core';
import {FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms';
import {AppealsService, EmailEntry, HistoryService, MailService, MinecraftAppeal, PunishmentHistory} from '@api';
import {HeaderComponent} from '@header/header.component';
import {NgOptimizedImage} from '@angular/common';
import {MatButtonModule} from '@angular/material/button';
import {MatIconModule} from '@angular/material/icon';
import {AuthService} from '@services/auth.service';
import {MatProgressSpinnerModule} from '@angular/material/progress-spinner';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatSelectModule} from '@angular/material/select';
import {MatInputModule} from '@angular/material/input';
import {HistoryFormatService} from '@pages/reference/bans/history-format.service';
import {MatDialog} from '@angular/material/dialog';
import {VerifyMailDialogComponent} from '@pages/forms/verify-mail-dialog/verify-mail-dialog.component';
import {Router} from '@angular/router';
import {FullSizeComponent} from '@shared-components/full-size/full-size.component';
import {finalize} from 'rxjs';

@Component({
  selector: 'app-appeal',
  imports: [
    HeaderComponent,
    NgOptimizedImage,
    MatButtonModule,
    MatIconModule,
    MatProgressSpinnerModule,
    MatFormFieldModule,
    MatSelectModule,
    MatInputModule,
    ReactiveFormsModule,
    FullSizeComponent,
  ],
  templateUrl: './appeal.component.html',
  styleUrl: './appeal.component.scss'
})
export class AppealComponent implements OnInit, OnDestroy {

  private mailService = inject(MailService);
  private historyFormatService = inject(HistoryFormatService);
  private appealsService = inject(AppealsService);
  private historyService = inject(HistoryService);
  public authService = inject(AuthService);
  private resizeObserver: ResizeObserver | null = null;
  private boundHandleResize: any;

  protected form: FormGroup<Appeal>;
  protected history = signal<PunishmentHistory[] | null>(null);
  protected selectedPunishment = signal<PunishmentHistory | null>(null);
  private emails = signal<EmailEntry[]>([]);
  protected verifiedEmails = computed(() => this.emails()
    .filter(email => email.verified)
    .map(email => email.email.toLowerCase()));
  protected emailIsValid = signal<boolean>(false);
  protected dialog = inject(MatDialog);

  constructor() {
    this.form = new FormGroup({
      email: new FormControl('', {nonNullable: true, validators: [Validators.required, Validators.email]}),
      appeal: new FormControl('', {nonNullable: true, validators: [Validators.required, Validators.minLength(10)]})
    });
    this.mailService.getUserEmails().subscribe(emails => {
      this.emails.set(emails);
    });
    this.form.valueChanges.subscribe(() => {
      if (this.verifiedEmails().includes(this.form.getRawValue().email.toLowerCase())) {
        this.emailIsValid.set(true);
      } else {
        this.emailIsValid.set(false);
      }
    });
    computed(() => {
      if (this.verifiedEmails().length > 0) {
        this.form.get('email')?.setValue(this.verifiedEmails()[0]);
        this.emailIsValid.set(true);
      }
    });
  }

  ngOnInit() {
    const uuid = this.authService.getUuid();
    if (uuid === null) {
      throw new Error('JWT subject is null, are you logged in?');
    }
    this.historyService.getAllHistoryForUUID(uuid).subscribe(history => {
      this.history.set(history.filter(item => this.historyFormatService.isActive(item)));
    })
  }

  ngOnDestroy() {
    if (this.resizeObserver) {
      this.resizeObserver.disconnect();
      this.resizeObserver = null;
    }

    if (this.boundHandleResize) {
      window.removeEventListener('resize', this.boundHandleResize);
    }
  }

  public onSubmit() {
    if (this.form === undefined) {
      console.error('Form is undefined');
      return
    }
    if (this.form.valid) {
      this.sendForm()
    } else {
      Object.keys(this.form.controls).forEach(field => {
        const control = this.form!.get(field);
        if (!(control instanceof FormGroup)) {
          console.error('Control [' + control + '] is not a FormGroup');
          return;
        }
        control.markAsTouched({onlySelf: true});
      });
    }
  }

  private router = inject(Router)

  protected formSubmitting: boolean = false;

  private sendForm() {
    if (this.formSubmitting) {
      return;
    }
    this.formSubmitting = true;
    const rawValue = this.form.getRawValue();
    const uuid = this.authService.getUuid();
    if (uuid === null) {
      throw new Error('JWT subject is null, are you logged in?');
    }
    const appeal: MinecraftAppeal = {
      appeal: rawValue.appeal,
      email: rawValue.email,
      punishmentId: this.selectedPunishment()!.id,
      punishmentType: this.selectedPunishment()!.type,
      username: this.authService.username()!,
      uuid: uuid
    }
    this.appealsService.submitMinecraftAppeal(appeal)
      .pipe(
        finalize(() => this.formSubmitting = false)
      )
      .subscribe((result) => {
        if (!result.verified_mail) {
          throw new Error('Mail not verified');
        }
        this.router.navigate(['/forms/sent'], {
          state: {message: result.message}
        }).then();
      })
  }

  public currentPageIndex: number = 0;
  public totalPages: number[] = [0];

  public goToPage(pageIndex: number): void {
    if (pageIndex >= 0 && pageIndex < this.totalPages.length) {
      this.currentPageIndex = pageIndex;
    }
  }

  public previousPage() {
    this.goToPage(this.currentPageIndex - 1);
  }

  public nextPage() {
    if (this.currentPageIndex === this.totalPages.length - 1) {
      this.totalPages.push(this.currentPageIndex + 1);
    }
    this.goToPage(this.currentPageIndex + 1);
  }

  public isFirstPage(): boolean {
    return this.currentPageIndex === 0;
  }

  public isLastPage(): boolean {
    return this.currentPageIndex === this.totalPages.length - 1;
  }

  protected readonly length = length;

  onPunishmentSelected($event: PunishmentHistory) {
    this.selectedPunishment.set($event);
  }

  protected validateMailOrNextPage() {
    if (this.emailIsValid()) {
      this.nextPage();
      return;
    }
    const dialogRef = this.dialog.open(VerifyMailDialogComponent, {
      data: {email: this.form.getRawValue().email},
    });
    dialogRef.afterClosed().subscribe(result => {
      if (result === true) {
        this.emailIsValid.set(true);
      }
    });
  }
}

interface Appeal {
  email: FormControl<string>;
  appeal: FormControl<string>;
}
