import { Component, inject, OnInit, signal, computed } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { TableModule } from 'primeng/table';
import { ButtonModule } from 'primeng/button';
import { InputTextModule } from 'primeng/inputtext';
import { SelectModule } from 'primeng/select';
import { ToggleSwitchModule } from 'primeng/toggleswitch';
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, FormDialogComponent } from '../../shared';
import { AccountsActions, selectAllAccounts } from '../../core/store';
import { ExpenseRevenueService } from '../../core/services/expense-revenue.service';
import { SettingService } from '../../core/services/setting.service';
import { AccountService } from '../../core/services/account.service';
import { ExpenseRevenueCategory } from '../../core/models/expense-revenue.model';
import { Account } from '../../core/models/account.model';

interface TreeRow extends ExpenseRevenueCategory {
  depth: number;
  expanded: boolean;
  visible: boolean;
  hasChildren: boolean;
}

@Component({
  selector: 'app-expense-categories',
  standalone: true,
  imports: [
    CommonModule, ReactiveFormsModule, TranslateModule,
    TableModule, ButtonModule, InputTextModule, SelectModule,
    ToggleSwitchModule, TagModule, ToastModule, ConfirmDialogModule, TooltipModule,
    PageHeaderComponent, FormDialogComponent,
  ],
  providers: [MessageService, ConfirmationService],
  templateUrl: './expense-categories.component.html',
  styleUrl: './expense-categories.component.scss',
})
export class ExpenseCategoriesComponent implements OnInit {
  private fb = inject(FormBuilder);
  private store = inject(Store);
  private messageService = inject(MessageService);
  private confirmationService = inject(ConfirmationService);
  private translate = inject(TranslateService);
  private service = inject(ExpenseRevenueService);
  private settingService = inject(SettingService);
  private accountService = inject(AccountService);

  accounts$ = this.store.select(selectAllAccounts);
  allAccounts = signal<Account[]>([]);
  items = signal<ExpenseRevenueCategory[]>([]);
  treeRows = signal<TreeRow[]>([]);
  loading = signal(false);
  saving = signal(false);
  dialogVisible = signal(false);
  editing = signal<ExpenseRevenueCategory | null>(null);
  form!: FormGroup;
  detailAccounts = signal<Account[]>([]);
  defaultExpenseAccountId: number | null = null;

  visibleRows = computed(() => this.treeRows().filter(r => r.visible));

  /** Flat list of all categories for parent dropdown (excluding current editing item and its children) */
  parentOptions = computed(() => {
    const editId = this.editing()?.id;
    return this.items().filter(i => i.id !== editId);
  });

  ngOnInit(): void {
    this.form = this.fb.group({
      name: ['', Validators.required],
      name_en: [''],
      name_ar: [''],
      parent_id: [null],
      account_id: [null],
      description: [''],
      is_active: [true],
    });
    this.store.dispatch(AccountsActions.loadAccounts({}));
    this.accounts$.subscribe(a => {
      this.allAccounts.set(a);
      this.detailAccounts.set(a.filter(x => x.account_type === 'detail'));
    });
    this.settingService.getByKey('accounting.default_expense_account').subscribe({
      next: (res: any) => { const v = res?.data?.value ?? res?.value; this.defaultExpenseAccountId = v && v !== '0' ? Number(v) : null; },
      error: () => {},
    });
    this.loadData();
  }

  loadData(): void {
    this.loading.set(true);
    this.service.listCategoryTree('expense').subscribe({
      next: (res) => {
        this.items.set(this.flattenAll(res.data));
        this.buildTree(res.data);
        this.loading.set(false);
      },
      error: (err) => { this.loading.set(false); this.showError(err); },
    });
  }

  private flattenAll(nodes: ExpenseRevenueCategory[]): ExpenseRevenueCategory[] {
    const result: ExpenseRevenueCategory[] = [];
    const walk = (items: ExpenseRevenueCategory[]) => {
      for (const item of items) {
        result.push(item);
        if (item.children?.length) walk(item.children);
      }
    };
    walk(nodes);
    return result;
  }

  private buildTree(data: ExpenseRevenueCategory[]): void {
    const rows: TreeRow[] = [];
    const flatten = (nodes: ExpenseRevenueCategory[], depth: number, parentVisible: boolean) => {
      for (const node of nodes) {
        const hasChildren = !!(node.children?.length);
        const row: TreeRow = { ...node, depth, expanded: true, visible: parentVisible, hasChildren };
        rows.push(row);
        if (node.children?.length) {
          flatten(node.children, depth + 1, parentVisible && row.expanded);
        }
      }
    };
    flatten(data, 0, true);
    this.treeRows.set(rows);
  }

  toggleExpand(row: TreeRow): void {
    row.expanded = !row.expanded;
    this.updateVisibility();
  }

  private updateVisibility(): void {
    const rows = this.treeRows();
    const parentStack: { depth: number; expanded: boolean }[] = [];
    for (const row of rows) {
      while (parentStack.length > 0 && parentStack[parentStack.length - 1].depth >= row.depth) {
        parentStack.pop();
      }
      if (parentStack.length === 0) {
        row.visible = true;
      } else {
        row.visible = parentStack.every(p => p.expanded);
      }
      parentStack.push({ depth: row.depth, expanded: row.expanded });
    }
    this.treeRows.set([...rows]);
  }

  openNew(parentId?: number | null): void {
    this.editing.set(null);
    this.form.reset({ is_active: true, parent_id: parentId ?? null });
    this.dialogVisible.set(true);
  }

  edit(item: ExpenseRevenueCategory): void {
    this.editing.set(item);
    this.form.patchValue(item);
    this.dialogVisible.set(true);
  }

  delete(item: ExpenseRevenueCategory): void {
    this.confirmationService.confirm({
      message: this.translate.instant('EXPENSE_CAT.CONFIRM_DELETE'),
      header: this.translate.instant('COMMON.CONFIRM'),
      icon: 'pi pi-exclamation-triangle',
      acceptButtonStyleClass: 'p-button-danger',
      accept: () => {
        this.saving.set(true);
        this.service.deleteCategory('expense', item.id).subscribe({
          next: () => { this.saving.set(false); this.loadData(); this.showSuccess('EXPENSE_CAT.DELETE_SUCCESS'); },
          error: (err) => { this.saving.set(false); this.showError(err); },
        });
      },
    });
  }

  onSave(): void {
    if (this.form.valid) {
      this.saving.set(true);
      const data = { ...this.form.value };

      if (data.account_id) {
        this.saveCategory(data);
      } else {
        // Find parent account ID: from parent category or default setting
        let parentAccountId: number | null = null;
        if (data.parent_id) {
          const parentCat = this.items().find(i => i.id === data.parent_id);
          if (parentCat?.account_id) parentAccountId = parentCat.account_id;
        }
        if (!parentAccountId && this.defaultExpenseAccountId) {
          parentAccountId = this.defaultExpenseAccountId;
        }

        if (parentAccountId) {
          this.autoCreateAccount(parentAccountId, data);
        } else {
          this.saveCategory(data);
        }
      }
    } else { this.form.markAllAsTouched(); }
  }

  /** Fetch parent account from API, generate next code, create detail account (retries on code conflict) */
  private autoCreateAccount(parentAccountId: number, data: any): void {
    const catName = data.name || data.name_ar || '';
    this.accountService.getById(parentAccountId).subscribe({
      next: (parentRes) => {
        const parentAcc = parentRes.data;
        this.accountService.listAll().subscribe({
          next: (allRes) => {
            const siblings = allRes.data.filter(a => a.parent_id === parentAcc.id);
            const maxSeq = siblings.reduce((max, s) => {
              const suffix = s.code.slice(parentAcc.code.length);
              const num = parseInt(suffix, 10);
              return isNaN(num) ? max : Math.max(max, num);
            }, 0);
            this.tryCreateAccount(parentAcc, catName, data, maxSeq + 1, 0);
          },
          error: () => { this.saveCategory(data); },
        });
      },
      error: () => { this.saveCategory(data); },
    });
  }

  private tryCreateAccount(parentAcc: Account, catName: string, data: any, seq: number, retries: number): void {
    const code = parentAcc.code + String(seq).padStart(2, '0');
    this.accountService.create({
      name: catName,
      name_ar: data.name_ar || catName,
      name_en: data.name_en || '',
      code,
      parent_id: parentAcc.id,
      classification: parentAcc.classification,
      nature: parentAcc.nature || 'debit',
      account_type: 'detail',
    }).subscribe({
      next: (accRes) => {
        data.account_id = accRes.data.id;
        this.store.dispatch(AccountsActions.loadAccounts({ force: true }));
        this.saveCategory(data);
      },
      error: () => {
        if (retries < 50) {
          this.tryCreateAccount(parentAcc, catName, data, seq + 1, retries + 1);
        } else {
          this.saveCategory(data);
        }
      },
    });
  }

  private saveCategory(data: any): void {
    const obs = this.editing()
      ? this.service.updateCategory('expense', this.editing()!.id, data)
      : this.service.createCategory('expense', data);
    obs.subscribe({
      next: () => {
        this.saving.set(false);
        this.dialogVisible.set(false);
        this.loadData();
        this.showSuccess(this.editing() ? 'EXPENSE_CAT.UPDATE_SUCCESS' : 'EXPENSE_CAT.CREATE_SUCCESS');
      },
      error: (err) => { this.saving.set(false); this.showError(err); },
    });
  }

  retry(): void { this.loadData(); }
  private showError(err: any): void { this.messageService.add({ severity: 'error', summary: this.translate.instant('COMMON.ERROR'), detail: err.error?.message || 'Failed' }); }
  private showSuccess(key: string): void { this.messageService.add({ severity: 'success', summary: this.translate.instant('COMMON.SUCCESS'), detail: this.translate.instant(key) }); }
}
