import { Component, inject, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
import { MatDialogModule, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatChipsModule } from '@angular/material/chips';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { ApprovalService } from '../services/approval.service';
import { NotificationService } from '../../../core/services/notification.service';
import { ApprovalResponseDto, RejectionReason, DocumentType } from '../../../api/models';
import {
  INPUT_LIMITS,
  noScriptValidator,
  noNullBytesValidator,
  notOnlyWhitespaceValidator,
  normalizeWhitespace,
} from '../../../shared/utils/form-validators';
import { createSubmitDebounce } from '../../../shared/utils/form-utils';

export interface ApprovalActionDialogData {
  approval: ApprovalResponseDto;
  action: 'approve' | 'reject' | 'changes';
}

@Component({
  selector: 'app-approval-action',
  standalone: true,
  imports: [
    CommonModule,
    ReactiveFormsModule,
    MatDialogModule,
    MatFormFieldModule,
    MatInputModule,
    MatSelectModule,
    MatButtonModule,
    MatIconModule,
    MatChipsModule,
    MatProgressSpinnerModule,
  ],
  template: `
    <h2 mat-dialog-title>{{ dialogTitle }}</h2>
    <mat-dialog-content>
      <form [formGroup]="form" class="action-form">
        <mat-form-field appearance="outline">
          <mat-label>Remarks</mat-label>
          <textarea
            matInput
            formControlName="remarks"
            rows="4"
            [placeholder]="remarksPlaceholder"
            [maxlength]="limits.DESCRIPTION_MAX"
          ></textarea>
          @if (form.controls.remarks.hasError('required')) {
            <mat-error>Remarks are required</mat-error>
          }
          @if (form.controls.remarks.hasError('minlength')) {
            <mat-error>Remarks must be at least 10 characters</mat-error>
          }
          @if (form.controls.remarks.hasError('maxlength')) {
            <mat-error>Maximum {{ limits.DESCRIPTION_MAX }} characters allowed</mat-error>
          }
          @if (form.controls.remarks.hasError('dangerousContent')) {
            <mat-error>Invalid characters detected</mat-error>
          }
          <mat-hint align="end">{{ form.controls.remarks.value?.length || 0 }}/{{ limits.DESCRIPTION_MAX }}</mat-hint>
        </mat-form-field>

        @if (data.action === 'reject') {
          <mat-form-field appearance="outline">
            <mat-label>Rejection Reason</mat-label>
            <mat-select formControlName="rejectionReason">
              @for (reason of rejectionReasons; track reason.value) {
                <mat-option [value]="reason.value">{{ reason.label }}</mat-option>
              }
            </mat-select>
            @if (form.controls.rejectionReason.hasError('required')) {
              <mat-error>Please select a rejection reason</mat-error>
            }
          </mat-form-field>
        }

        @if (data.action === 'changes') {
          <mat-form-field appearance="outline">
            <mat-label>Required Documents</mat-label>
            <mat-select formControlName="requiredDocuments" multiple>
              @for (docType of documentTypes; track docType.value) {
                <mat-option [value]="docType.value">{{ docType.label }}</mat-option>
              }
            </mat-select>
            <mat-hint>Select documents the applicant needs to provide</mat-hint>
          </mat-form-field>
        }
      </form>
    </mat-dialog-content>
    <mat-dialog-actions align="end">
      <button mat-button (click)="onCancel()" [disabled]="submitting()">Cancel</button>
      <button
        mat-raised-button
        [color]="actionColor"
        (click)="onSubmit()"
        [disabled]="form.invalid || submitting()"
      >
        @if (submitting()) {
          <mat-spinner diameter="20"></mat-spinner>
        } @else {
          {{ actionLabel }}
        }
      </button>
    </mat-dialog-actions>
  `,
  styles: [
    `
      .action-form {
        display: flex;
        flex-direction: column;
        gap: 16px;
        min-width: 400px;
      }
    `,
  ],
})
export class ApprovalActionComponent {
  private readonly fb = inject(FormBuilder);
  private readonly approvalService = inject(ApprovalService);
  private readonly notification = inject(NotificationService);
  private readonly dialogRef = inject(MatDialogRef<ApprovalActionComponent>);
  readonly data: ApprovalActionDialogData = inject(MAT_DIALOG_DATA);

  /** Debounce handler to prevent double-click submissions */
  private readonly submitDebounce = createSubmitDebounce(500);

  readonly submitting = signal(false);

  /** Input limits exposed for template binding */
  readonly limits = INPUT_LIMITS;

  readonly rejectionReasons: { value: RejectionReason; label: string }[] = [
    { value: 'DOCUMENTATION_INCOMPLETE', label: 'Documentation Incomplete' },
    { value: 'INCOMPLETE_DOCUMENTS', label: 'Incomplete Documents' },
    { value: 'ELIGIBILITY_CRITERIA_NOT_MET', label: 'Eligibility Criteria Not Met' },
    { value: 'INCOMPLETE_INFORMATION', label: 'Incomplete Information' },
    { value: 'POLICY_VIOLATION', label: 'Policy Violation' },
    { value: 'FRAUD_SUSPECTED', label: 'Fraud Suspected' },
    { value: 'OTHER', label: 'Other' },
  ];

  readonly documentTypes: { value: DocumentType; label: string }[] = [
    { value: 'ID_PROOF', label: 'Identity Proof' },
    { value: 'ADDRESS_PROOF', label: 'Address Proof' },
    { value: 'FIRE_SAFETY', label: 'Fire Safety Certificate' },
    { value: 'FLOOR_PLAN', label: 'Floor Plan' },
    { value: 'SITE_PLAN', label: 'Site Plan' },
    { value: 'BUILDING_PERMIT', label: 'Building Permit' },
    { value: 'BUSINESS_LICENSE', label: 'Business License' },
    { value: 'PHOTOGRAPH', label: 'Photograph' },
    { value: 'NOC', label: 'No Objection Certificate' },
    { value: 'LICENSE_COPY', label: 'License Copy' },
    { value: 'HEALTH_CERT', label: 'Health Certificate' },
    { value: 'TAX_CLEARANCE', label: 'Tax Clearance' },
    { value: 'OTHER', label: 'Other Document' },
  ];

  readonly form = this.fb.nonNullable.group({
    remarks: ['', [
      Validators.required,
      Validators.minLength(10),
      Validators.maxLength(INPUT_LIMITS.DESCRIPTION_MAX),
      noScriptValidator(),
      noNullBytesValidator(),
      notOnlyWhitespaceValidator(),
    ]],
    rejectionReason: ['' as RejectionReason],
    requiredDocuments: [[] as string[]],
  });

  get dialogTitle(): string {
    switch (this.data.action) {
      case 'approve':
        return 'Approve Request';
      case 'reject':
        return 'Reject Request';
      case 'changes':
        return 'Request Changes';
    }
  }

  get actionLabel(): string {
    switch (this.data.action) {
      case 'approve':
        return 'Approve';
      case 'reject':
        return 'Reject';
      case 'changes':
        return 'Request Changes';
    }
  }

  get actionColor(): 'primary' | 'warn' {
    return this.data.action === 'reject' ? 'warn' : 'primary';
  }

  get remarksPlaceholder(): string {
    switch (this.data.action) {
      case 'approve':
        return 'Enter your approval remarks...';
      case 'reject':
        return 'Explain why this request is being rejected...';
      case 'changes':
        return 'Explain what changes are required...';
    }
  }

  constructor() {
    if (this.data.action === 'reject') {
      this.form.controls.rejectionReason.addValidators(Validators.required);
    }
  }

  onSubmit(): void {
    // Debounce to prevent double-click submissions
    this.submitDebounce(() => this.performSubmit());
  }

  private performSubmit(): void {
    // Prevent submission if already in progress
    if (this.submitting()) {
      return;
    }

    if (this.form.invalid) {
      this.form.markAllAsTouched();
      return;
    }

    this.submitting.set(true);
    const rawValues = this.form.getRawValue();
    const requestId = this.data.approval.requestId;

    // Normalize the remarks text
    const remarks = normalizeWhitespace(rawValues.remarks);
    const rejectionReason = rawValues.rejectionReason;
    const requiredDocuments = rawValues.requiredDocuments;

    let action$;
    switch (this.data.action) {
      case 'approve':
        action$ = this.approvalService.approve(requestId, { remarks });
        break;
      case 'reject':
        action$ = this.approvalService.reject(requestId, { remarks, rejectionReason });
        break;
      case 'changes':
        action$ = this.approvalService.requestChanges(requestId, { remarks, requiredDocuments });
        break;
    }

    action$.subscribe({
      next: () => {
        this.notification.success(
          this.data.action === 'approve'
            ? 'Request approved successfully'
            : this.data.action === 'reject'
            ? 'Request rejected'
            : 'Changes requested'
        );
        this.dialogRef.close(true);
      },
      error: (err) => {
        this.submitting.set(false);
        // Handle different error formats
        const errorMessage = err?.error?.message || err?.message || 'Failed to process action. Please try again.';
        this.notification.error(errorMessage);
      },
    });
  }

  onCancel(): void {
    this.dialogRef.close();
  }
}
