import { Component, OnInit, ViewChild } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { GridModule, CellClickEvent } from '@progress/kendo-angular-grid';
import { ButtonsModule } from '@progress/kendo-angular-buttons';
import { DialogsModule } from '@progress/kendo-angular-dialog';
import { InputsModule } from '@progress/kendo-angular-inputs';
import { DropDownsModule } from '@progress/kendo-angular-dropdowns';
import { DateInputsModule } from '@progress/kendo-angular-dateinputs';
import { ContextMenuModule, ContextMenuComponent, ContextMenuSelectEvent } from '@progress/kendo-angular-menu';
import { Payee1099ApiService } from '../../services/payee1099-api.service';
import { Payee1099ListItem, Payee1099, SavePayee1099Request } from '../../models/payee1099.model';
import { MemberApiService } from '../../../members/services/member-api.service';
import { MemberListItemDto, memberDisplayName } from '../../../members/models/member.model';
import { PageHeaderActionsDirective } from '../../../../shared/directives/page-header-actions.directive';
import { HasPermissionDirective } from '../../../../core/directives/has-permission.directive';

/** Flattened member item with a single displayName field for the picker. */
interface MemberOption { id: number; displayName: string; }

/** Editable form model for the New/Edit dialog. */
interface Payee1099Form {
  legalName: string;
  displayName: string;
  memberId: number | null;
  taxClassification: string;
  is1099Tracked: boolean;
  tinType: string;
  tin: string;
  addressLine1: string;
  addressLine2: string;
  city: string;
  state: string;
  zip: string;
  email: string;
  phone: string;
  w9Status: string;
  w9ReceivedDate: Date | null;
  isActive: boolean;
  notes: string;
}

@Component({
  selector: 'app-payee-1099-page',
  standalone: true,
  imports: [
    CommonModule, FormsModule, GridModule, ButtonsModule, DialogsModule,
    InputsModule, DropDownsModule, DateInputsModule, ContextMenuModule,
    PageHeaderActionsDirective, HasPermissionDirective,
  ],
  templateUrl: './payee-1099-page.component.html',
  styleUrls: ['./payee-1099-page.component.scss'],
})
export class Payee1099PageComponent implements OnInit {
  recipients: Payee1099ListItem[] = [];
  loading = false;
  includeInactive = false;

  readonly taxClassifications = ['Individual', 'SoleProprietor', 'Partnership', 'CCorp', 'SCorp', 'LLC', 'Other'];
  readonly tinTypes = ['SSN', 'EIN'];
  readonly w9Statuses = ['Missing', 'Requested', 'OnFile', 'Expired'];

  /** Member picker options, filled on demand from the members search. */
  memberResults: MemberOption[] = [];

  @ViewChild('rowMenu') rowMenu!: ContextMenuComponent;
  rowMenuItems: { text: string }[] = [];
  private contextRow: Payee1099ListItem | null = null;

  dialogOpen = false;
  editingId: number | null = null;
  /** Last-4 of the existing TIN (edit mode), so the TIN box can show a masked placeholder. */
  editingTinLast4: string | null = null;
  /** True when the record being edited already has a W-9 document attached. */
  editingHasW9 = false;
  /** Full TIN revealed on demand (write-gated); shown read-only, never logged or persisted. */
  revealedTin: string | null = null;
  /** Whether the user has manually toggled "1099 Tracked" in this dialog session (suppresses the classification default). */
  private trackedTouched = false;
  form: Payee1099Form = this.blankForm();

  constructor(
    private api: Payee1099ApiService,
    private memberApi: MemberApiService,
  ) {}

  ngOnInit(): void {
    this.load();
  }

  load(): void {
    this.loading = true;
    this.api.getAll(this.includeInactive).subscribe({
      next: (rows) => {
        this.recipients = rows;
        this.loading = false;
      },
      error: () => { this.loading = false; },
    });
  }

  private blankForm(): Payee1099Form {
    return {
      legalName: '', displayName: '', memberId: null,
      taxClassification: 'Individual', is1099Tracked: true,
      tinType: 'SSN', tin: '',
      addressLine1: '', addressLine2: '', city: '', state: '', zip: '',
      email: '', phone: '',
      w9Status: 'Missing', w9ReceivedDate: null,
      isActive: true, notes: '',
    };
  }

  // ── Member picker (server-side search, same source as the expense form) ──────
  onMemberFilter(term: string): void {
    if (!term || term.length < 1) { this.memberResults = []; return; }
    this.memberApi.getPaged({ search: term, pageSize: 10 }).subscribe((result) => {
      this.memberResults = result.items.map((member: MemberListItemDto) => ({
        id: member.id,
        displayName: memberDisplayName(member),
      }));
    });
  }

  // ── Row interaction: primary click opens the editor; right-click shows actions ──
  onCellClick(event: CellClickEvent): void {
    if (event.type === 'contextmenu') {
      event.originalEvent.preventDefault();
      this.contextRow = event.dataItem;
      this.rowMenuItems = this.buildMenuItems(event.dataItem.isActive);
      this.rowMenu.show({ left: event.originalEvent.pageX, top: event.originalEvent.pageY });
    } else {
      this.openEdit(event.dataItem);
    }
  }

  onRowMenuSelect(event: ContextMenuSelectEvent): void {
    if (!this.contextRow) return;
    if (event.item.text === 'Edit') this.openEdit(this.contextRow);
    else if (event.item.text === 'Deactivate') this.deactivate(this.contextRow);
  }

  private buildMenuItems(isActive: boolean): { text: string }[] {
    const items: { text: string }[] = [{ text: 'Edit' }];
    if (isActive) items.push({ text: 'Deactivate' });
    return items;
  }

  // ── Dialog open ──────────────────────────────────────────────────────────────
  openNew(): void {
    this.editingId = null;
    this.editingTinLast4 = null;
    this.editingHasW9 = false;
    this.revealedTin = null;
    this.trackedTouched = false;
    this.form = this.blankForm();
    this.dialogOpen = true;
  }

  openEdit(row: Payee1099ListItem): void {
    this.editingId = row.id;
    this.editingHasW9 = false;
    this.revealedTin = null;
    this.trackedTouched = false;
    this.dialogOpen = true;
    // Load the full record so the dialog can prefill the address/contact/notes fields.
    this.api.getById(row.id).subscribe((payee: Payee1099) => {
      this.editingTinLast4 = payee.tinLast4 ?? null;
      this.editingHasW9 = payee.hasW9Document;
      this.form = {
        legalName: payee.legalName,
        displayName: payee.displayName ?? '',
        memberId: payee.memberId ?? null,
        taxClassification: payee.taxClassification,
        is1099Tracked: payee.is1099Tracked,
        tinType: payee.tinType ?? 'SSN',
        tin: '',
        addressLine1: payee.addressLine1 ?? '',
        addressLine2: payee.addressLine2 ?? '',
        city: payee.city ?? '',
        state: payee.state ?? '',
        zip: payee.zip ?? '',
        email: payee.email ?? '',
        phone: payee.phone ?? '',
        w9Status: payee.w9Status,
        w9ReceivedDate: this.parseDateOnly(payee.w9ReceivedDate),
        isActive: payee.isActive,
        notes: payee.notes ?? '',
      };
      // Seed the picker with the linked member so its name shows even before a search.
      if (payee.memberId != null && payee.memberName) {
        this.memberResults = [{ id: payee.memberId, displayName: payee.memberName }];
      }
    });
  }

  // ── Save ─────────────────────────────────────────────────────────────────────
  save(): void {
    if (!this.form.legalName.trim()) return;
    const typedTin = this.form.tin.trim();
    const request: SavePayee1099Request = {
      legalName: this.form.legalName.trim(),
      displayName: this.form.displayName.trim() || undefined,
      memberId: this.form.memberId ?? null,
      taxClassification: this.form.taxClassification,
      is1099Tracked: this.form.is1099Tracked,
      tinType: this.form.tinType,
      // Send the typed TIN when present. On edit a blank leaves the stored value
      // unchanged (null = no change); on new a blank simply means no TIN yet.
      tin: typedTin || null,
      addressLine1: this.form.addressLine1.trim() || undefined,
      addressLine2: this.form.addressLine2.trim() || undefined,
      city: this.form.city.trim() || undefined,
      state: this.form.state.trim() || undefined,
      zip: this.form.zip.trim() || undefined,
      email: this.form.email.trim() || undefined,
      phone: this.form.phone.trim() || undefined,
      w9Status: this.form.w9Status,
      w9ReceivedDate: this.toDateOnly(this.form.w9ReceivedDate),
      isActive: this.form.isActive,
      notes: this.form.notes.trim() || undefined,
    };
    const done = () => { this.dialogOpen = false; this.load(); };
    if (this.editingId == null) this.api.create(request).subscribe(done);
    else this.api.update(this.editingId, request).subscribe(done);
  }

  deactivate(row: Payee1099ListItem): void {
    if (!confirm(`Deactivate "${row.legalName}"?`)) return;
    this.api.delete(row.id).subscribe(() => this.load());
  }

  // ── Tax classification drives the 1099-tracked default (spec §2.1/§2.3) ────────
  // Corporations default to NOT tracked; everyone else defaults to tracked. Only applies
  // to NEW records and only until the user manually flips the toggle (no override of an
  // explicit choice or an existing saved value on edit).
  onTaxClassificationChange(classification: string): void {
    if (this.editingId != null || this.trackedTouched) return;
    const isCorporation = classification === 'CCorp' || classification === 'SCorp';
    this.form.is1099Tracked = !isCorporation;
  }

  onTrackedToggle(): void { this.trackedTouched = true; }

  // ── W-9 document upload/view (edit mode only; a new record is saved first) ─────
  onW9FileSelected(event: Event): void {
    const input = event.target as HTMLInputElement;
    const file = input.files?.[0] ?? null;
    if (!file || this.editingId == null) return;
    this.api.uploadW9(this.editingId, file).subscribe(() => {
      this.editingHasW9 = true;
      input.value = '';
    });
  }

  /** Fetch the stored W-9 via HttpClient (auth interceptor attaches the JWT) and open it in a new tab. */
  viewW9(): void {
    if (this.editingId == null) return;
    this.api.downloadW9(this.editingId).subscribe((blob) => {
      const url = URL.createObjectURL(blob);
      window.open(url, '_blank');
      setTimeout(() => URL.revokeObjectURL(url), 60_000);
    });
  }

  // ── Full TIN reveal (write-gated; acceptance criterion #11.4) ──────────────────
  revealTin(): void {
    if (this.editingId == null) return;
    this.api.revealTin(this.editingId).subscribe((result) => {
      this.revealedTin = result.tin;
    });
  }

  // ── Date-only helpers: build/parse "yyyy-MM-dd" from LOCAL components ─────────
  private parseDateOnly(value: string | undefined | null): Date | null {
    if (!value) return null;
    const [year, month, day] = value.split('-').map(Number);
    return new Date(year, month - 1, day);
  }

  private toDateOnly(date: Date | null): string | null {
    if (!date) return null;
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
  }
}
