import { Component, inject, OnInit, OnDestroy, signal, computed } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormBuilder, FormGroup, FormArray, ReactiveFormsModule, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { Subscription } from 'rxjs';
import { take } from 'rxjs/operators';
import { TableModule } from 'primeng/table';
import { ButtonModule } from 'primeng/button';
import { DialogModule } from 'primeng/dialog';
import { InputTextModule } from 'primeng/inputtext';
import { InputNumberModule } from 'primeng/inputnumber';
import { TextareaModule } from 'primeng/textarea';
import { SelectModule } from 'primeng/select';
import { DatePickerModule } from 'primeng/datepicker';
import { TagModule } from 'primeng/tag';
import { ToastModule } from 'primeng/toast';
import { ConfirmDialogModule } from 'primeng/confirmdialog';
import { TooltipModule } from 'primeng/tooltip';
import { MessageService, ConfirmationService } from 'primeng/api';
import { PageHeaderComponent, DataTableComponent, FormDialogComponent, TableColumn } from '../../shared';
import {
  JournalEntriesActions,
  selectJournalEntriesSaving,
  selectJournalEntriesError,
  AccountsActions,
  selectAllAccounts,
  selectAllCostCenters,
  CostCentersActions,
  selectAllCurrencies,
  CurrenciesActions,
  FiscalYearsActions,
  selectAllFiscalYears,
} from '../../core/store';
import { JournalEntry, JournalEntryLine } from '../../core/models/journal-entry.model';
import { JournalEntryService } from '../../core/services/journal-entry.service';
import { Account } from '../../core/models/account.model';
import { FiscalYear } from '../../core/models/fiscal-year.model';

@Component({
  selector: 'app-journal-entries',
  standalone: true,
  imports: [
    CommonModule,
    ReactiveFormsModule,
    TranslateModule,
    TableModule,
    ButtonModule,
    DialogModule,
    InputTextModule,
    InputNumberModule,
    TextareaModule,
    SelectModule,
    DatePickerModule,
    TagModule,
    ToastModule,
    ConfirmDialogModule,
    TooltipModule,
    PageHeaderComponent,
    DataTableComponent,
    FormDialogComponent,
  ],
  providers: [MessageService, ConfirmationService],
  templateUrl: './journal-entries.component.html',
  styleUrl: './journal-entries.component.scss',
})
export class JournalEntriesComponent implements OnInit, OnDestroy {
  private fb = inject(FormBuilder);
  private store = inject(Store);
  private router = inject(Router);
  private messageService = inject(MessageService);
  private confirmationService = inject(ConfirmationService);
  private translate = inject(TranslateService);
  private service = inject(JournalEntryService);
  private langSub!: Subscription;

  /** Map source_type to route prefix */
  private readonly sourceRouteMap: Record<string, string> = {
    'expense': '/accounting/expenses',
    'revenue': '/accounting/revenues',
    'receipt_voucher': '/accounting/receipt-vouchers',
    'payment_voucher': '/accounting/payment-vouchers',
    'stock_receipt': '/core/stock-receipts',
    'stock_issue': '/core/stock-issues',
    'warehouse_transfer': '/core/warehouse-transfers',
    'stock_adjustment': '/core/stock-adjustments',
    'inventory_count': '/core/inventory-counts',
    'opening_balance': '/accounting/opening-balances',
    'opening_balance_inventory': '/core/opening-balance-inventory',
    'fixed_asset': '/accounting/fixed-assets',
    'asset_depreciation': '/accounting/fixed-assets',
    'bank_transfer': '/accounting/transfers',
    'check_received': '/accounting/checks-received',
    'check_issued': '/accounting/checks-issued',
    'petty_cash': '/accounting/petty-cash',
    'year_end_closing': '/accounting/year-end-closing',
    'debt_change': '/accounting/ar-ap',
    'allocation': '/accounting/allocation-rules',
    'recurring_entry': '/accounting/recurring-entries',
    'sales_invoice': '/sales/invoices',
    'sales_payment': '/sales/invoices',
    'reversal_sales_invoice': '/sales/invoices',
  };

  readonly columns: TableColumn[] = [
    { field: 'entry_number', header: 'JOURNAL_ENTRIES.NUMBER' },
    { field: 'date', header: 'JOURNAL_ENTRIES.DATE', sortable: true },
    { field: 'reference', header: 'JOURNAL_ENTRIES.REFERENCE' },
    { field: 'source_type', header: 'JOURNAL_ENTRIES.SOURCE' },
    { field: 'description', header: 'JOURNAL_ENTRIES.DESCRIPTION' },
    { field: 'fiscal_year', header: 'JOURNAL_ENTRIES.FISCAL_YEAR' },
    { field: 'total_debit', header: 'JOURNAL_ENTRIES.TOTAL_DEBIT' },
    { field: 'total_credit', header: 'JOURNAL_ENTRIES.TOTAL_CREDIT' },
    { field: 'status', header: 'COMMON.STATUS' },
    { field: 'actions', header: 'COMMON.ACTIONS' },
  ];

  saving$ = this.store.select(selectJournalEntriesSaving);
  error$ = this.store.select(selectJournalEntriesError);
  accounts$ = this.store.select(selectAllAccounts);
  costCenters$ = this.store.select(selectAllCostCenters);
  currencies$ = this.store.select(selectAllCurrencies);
  fiscalYears$ = this.store.select(selectAllFiscalYears);

  // Server-side pagination
  tableData = signal<JournalEntry[]>([]);
  totalRecords = signal(0);
  tableLoading = signal(false);
  first = 0;
  rows = 25;

  dialogVisible = signal(false);
  viewDialogVisible = signal(false);
  editingEntry = signal<JournalEntry | null>(null);
  viewingEntry = signal<JournalEntry | null>(null);
  entryForm!: FormGroup;

  detailAccounts = signal<Account[]>([]);
  fiscalYearMap = signal<Map<number, string>>(new Map());

  ngOnInit(): void {
    this.initForm();
    this.langSub = this.translate.onLangChange.subscribe(() => {});
    this.loadPage();
    this.store.dispatch(AccountsActions.loadAccounts({}));
    this.store.dispatch(CostCentersActions.loadCostCenters({}));
    this.store.dispatch(CurrenciesActions.loadCurrencies({}));
    this.store.dispatch(FiscalYearsActions.loadFiscalYears({}));

    this.accounts$.subscribe(accounts => {
      this.detailAccounts.set(accounts.filter(a => a.account_type === 'detail'));
    });
    this.fiscalYears$.subscribe(years => {
      const map = new Map<number, string>();
      years.forEach(y => map.set(y.id, y.name));
      this.fiscalYearMap.set(map);
    });
  }

  ngOnDestroy(): void {
    this.langSub?.unsubscribe();
  }

  private initForm(): void {
    this.entryForm = this.fb.group({
      date: [new Date(), Validators.required],
      fiscal_year_id: [null],
      reference: [''],
      description: [''],
      lines: this.fb.array([]),
    });
  }

  get lines(): FormArray {
    return this.entryForm.get('lines') as FormArray;
  }

  private createLine(line?: JournalEntryLine): FormGroup {
    return this.fb.group({
      account_id: [line?.account_id || null, Validators.required],
      debit: [line?.debit || 0],
      credit: [line?.credit || 0],
      cost_center_id: [line?.cost_center_id || null],
      description: [line?.description || ''],
    });
  }

  addLine(): void {
    this.lines.push(this.createLine());
  }

  removeLine(index: number): void {
    this.lines.removeAt(index);
  }

  get totalDebit(): number {
    return this.lines.controls.reduce((sum, line) => sum + (line.get('debit')?.value || 0), 0);
  }

  get totalCredit(): number {
    return this.lines.controls.reduce((sum, line) => sum + (line.get('credit')?.value || 0), 0);
  }

  get isBalanced(): boolean {
    return Math.abs(this.totalDebit - this.totalCredit) < 0.001;
  }

  openNew(): void {
    this.editingEntry.set(null);
    this.entryForm.reset({ date: new Date(), fiscal_year_id: null, reference: '', description: '' });
    this.lines.clear();
    this.addLine();
    this.addLine();
    this.dialogVisible.set(true);
  }

  editEntry(entry: JournalEntry): void {
    if (entry.status !== 'draft') return;
    this.editingEntry.set(entry);
    this.entryForm.patchValue({
      date: new Date(entry.date),
      fiscal_year_id: entry.fiscal_year_id || null,
      reference: entry.reference || '',
      description: entry.description || '',
    });
    this.lines.clear();
    (entry.lines || []).forEach(line => {
      this.lines.push(this.createLine(line));
    });
    if (this.lines.length < 2) {
      while (this.lines.length < 2) this.addLine();
    }
    this.dialogVisible.set(true);
  }

  viewEntry(entry: JournalEntry): void {
    this.viewingEntry.set(entry);
    this.viewDialogVisible.set(true);
  }

  loadPage(page = 1, perPage = this.rows): void {
    this.tableLoading.set(true);
    this.service.list(page, perPage).subscribe({
      next: (res) => {
        this.tableData.set(res.data);
        this.totalRecords.set(res.meta.total);
        this.tableLoading.set(false);
      },
      error: () => this.tableLoading.set(false),
    });
  }

  private reloadCurrentPage(): void {
    const currentPage = Math.floor(this.first / this.rows) + 1;
    this.loadPage(currentPage);
  }

  deleteEntry(entry: JournalEntry): void {
    if (entry.status !== 'draft') return;
    this.confirmationService.confirm({
      message: this.translate.instant('JOURNAL_ENTRIES.CONFIRM_DELETE'),
      header: this.translate.instant('COMMON.CONFIRM'),
      icon: 'pi pi-exclamation-triangle',
      acceptButtonStyleClass: 'p-button-danger',
      accept: () => {
        this.store.dispatch(JournalEntriesActions.deleteJournalEntry({ id: entry.id }));
        this.watchSave('JOURNAL_ENTRIES.DELETE_SUCCESS');
      },
    });
  }

  approveEntry(entry: JournalEntry): void {
    this.store.dispatch(JournalEntriesActions.approveJournalEntry({ id: entry.id }));
    this.watchSave('JOURNAL_ENTRIES.APPROVE_SUCCESS');
  }

  postEntry(entry: JournalEntry): void {
    this.store.dispatch(JournalEntriesActions.postJournalEntry({ id: entry.id }));
    this.watchSave('JOURNAL_ENTRIES.POST_SUCCESS');
  }

  reverseEntry(entry: JournalEntry): void {
    this.confirmationService.confirm({
      message: this.translate.instant('JOURNAL_ENTRIES.CONFIRM_REVERSE'),
      header: this.translate.instant('COMMON.CONFIRM'),
      icon: 'pi pi-exclamation-triangle',
      acceptButtonStyleClass: 'p-button-warning',
      accept: () => {
        const today = new Date().toISOString().split('T')[0];
        this.store.dispatch(JournalEntriesActions.reverseJournalEntry({ id: entry.id, date: today }));
        this.watchSave('JOURNAL_ENTRIES.REVERSE_SUCCESS');
      },
    });
  }

  cancelEntry(entry: JournalEntry): void {
    this.confirmationService.confirm({
      message: this.translate.instant('JOURNAL_ENTRIES.CONFIRM_CANCEL'),
      header: this.translate.instant('COMMON.CONFIRM'),
      icon: 'pi pi-exclamation-triangle',
      acceptButtonStyleClass: 'p-button-danger',
      accept: () => {
        this.store.dispatch(JournalEntriesActions.cancelJournalEntry({ id: entry.id }));
        this.watchSave('JOURNAL_ENTRIES.CANCEL_SUCCESS');
      },
    });
  }

  onSave(): void {
    if (this.entryForm.valid && this.lines.length >= 2 && this.isBalanced) {
      const formValue = this.entryForm.value;
      const dateStr = this.formatDate(formValue.date);
      const data = {
        date: dateStr,
        fiscal_year_id: formValue.fiscal_year_id || undefined,
        reference: formValue.reference || undefined,
        description: formValue.description || undefined,
        lines: formValue.lines.map((line: any) => ({
          account_id: line.account_id,
          debit: line.debit || 0,
          credit: line.credit || 0,
          cost_center_id: line.cost_center_id || undefined,
          description: line.description || undefined,
        })),
      };

      if (this.editingEntry()) {
        this.store.dispatch(JournalEntriesActions.updateJournalEntry({ id: this.editingEntry()!.id, entry: data }));
      } else {
        this.store.dispatch(JournalEntriesActions.createJournalEntry({ entry: data }));
      }

      this.watchSave(
        this.editingEntry() ? 'JOURNAL_ENTRIES.UPDATE_SUCCESS' : 'JOURNAL_ENTRIES.CREATE_SUCCESS',
        true
      );
    } else {
      this.entryForm.markAllAsTouched();
      if (!this.isBalanced) {
        this.messageService.add({ severity: 'warn', summary: this.translate.instant('COMMON.ERROR'), detail: this.translate.instant('JOURNAL_ENTRIES.NOT_BALANCED') });
      }
    }
  }

  private watchSave(successKey: string, closeDialog = false): void {
    const sub = this.store.select(selectJournalEntriesSaving).subscribe((saving) => {
      if (!saving) {
        sub.unsubscribe();
        this.store.select(selectJournalEntriesError).pipe(take(1)).subscribe((error) => {
          if (error) {
            this.messageService.add({ severity: 'error', summary: this.translate.instant('COMMON.ERROR'), detail: error });
          } else {
            if (closeDialog) this.dialogVisible.set(false);
            this.messageService.add({ severity: 'success', summary: this.translate.instant('COMMON.SUCCESS'), detail: this.translate.instant(successKey) });
            this.reloadCurrentPage();
          }
        });
      }
    });
  }

  onPageChange(event: any): void {
    this.first = event.first;
    this.rows = event.rows;
    const page = Math.floor(event.first / event.rows) + 1;
    this.loadPage(page, event.rows);
  }

  retry(): void {
    this.loadPage();
  }

  getStatusSeverity(status: string): 'info' | 'warn' | 'success' | 'danger' | 'secondary' | 'contrast' {
    switch (status) {
      case 'draft': return 'warn';
      case 'approved': return 'info';
      case 'posted': return 'success';
      case 'reversed': return 'danger';
      case 'cancelled': return 'danger';
      default: return 'secondary';
    }
  }

  private formatDate(date: Date): string {
    const y = date.getFullYear();
    const m = String(date.getMonth() + 1).padStart(2, '0');
    const d = String(date.getDate()).padStart(2, '0');
    return `${y}-${m}-${d}`;
  }

  getFiscalYearName(fiscalYearId: number | null | undefined): string {
    if (!fiscalYearId) return '-';
    return this.fiscalYearMap().get(fiscalYearId) || '-';
  }

  getSourceLabel(sourceType: string | null | undefined): string {
    if (!sourceType) return '';
    const key = 'JOURNAL_ENTRIES.SOURCE_' + sourceType.toUpperCase();
    const translated = this.translate.instant(key);
    return translated !== key ? translated : sourceType.replace(/_/g, ' ');
  }

  /** Get the route for a source_type */
  getSourceRoute(sourceType: string | null | undefined): string | null {
    if (!sourceType) return null;
    return this.sourceRouteMap[sourceType] || null;
  }

  /** Navigate to source operation */
  navigateToSource(entry: JournalEntry): void {
    const route = this.getSourceRoute(entry.source_type);
    if (route) {
      const queryParams = entry.source_id ? { viewId: entry.source_id } : {};
      this.router.navigate([route], { queryParams });
    }
  }

  getAccountName(accountId: number, accounts: Account[]): string {
    const acc = accounts.find(a => a.id === accountId);
    if (!acc) return '';
    return this.translate.currentLang === 'ar' ? (acc.name_ar || acc.name) : (acc.name_en || acc.name);
  }
}
