import { TestBed } from '@angular/core/testing';
import { of, throwError } from 'rxjs';
import { AdminTransactionsFacade } from './admin-transactions.facade';
import { ADMIN_TRANSACTIONS_GATEWAY } from '../services/admin-transactions-gateway.token';
import { AdminTransactionsGateway } from '../services/admin-transactions-gateway.interface';
import { AdminTransaction } from '../models/admin-transaction.model';

function transaction(overrides: Partial<AdminTransaction> = {}): AdminTransaction {
  return {
    id: 't1',
    orderId: 'o1',
    orderNumber: '1001',
    type: 'payment',
    method: 'card',
    status: 'success',
    amount: 1000,
    currency: 'RUB',
    fraudFlag: false,
    audit: [],
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    ...overrides,
  };
}

describe('AdminTransactionsFacade', () => {
  let facade: AdminTransactionsFacade;
  let gateway: jasmine.SpyObj<AdminTransactionsGateway>;

  beforeEach(() => {
    gateway = jasmine.createSpyObj<AdminTransactionsGateway>('AdminTransactionsGateway', [
      'loadTransactions', 'retryFailed', 'setFraudFlag',
    ]);
    TestBed.configureTestingModule({ providers: [{ provide: ADMIN_TRANSACTIONS_GATEWAY, useValue: gateway }] });
    facade = TestBed.inject(AdminTransactionsFacade);
  });

  it('loads transactions and total on success', () => {
    gateway.loadTransactions.and.returnValue(of({ items: [transaction()], total: 1, page: 1, pageSize: 10 }));

    facade.loadList();

    expect(facade.transactions().length).toBe(1);
    expect(facade.total()).toBe(1);
  });

  it('clears the list and sets an error on failure', () => {
    gateway.loadTransactions.and.returnValue(throwError(() => new Error('x')));

    facade.loadList();

    expect(facade.transactions()).toEqual([]);
    expect(facade.error()).toBe('common.errorDescription');
  });

  it('updateFilters resets page to 1 for a non-page change', () => {
    gateway.loadTransactions.and.returnValue(of({ items: [], total: 0, page: 1, pageSize: 10 }));

    facade.updateFilters({ page: 3 });
    facade.updateFilters({ search: 'x' });

    expect(facade.filters().page).toBe(1);
  });

  it('retryFailed reloads the list after the gateway call resolves', () => {
    gateway.retryFailed.and.returnValue(of(transaction()));
    gateway.loadTransactions.and.returnValue(of({ items: [], total: 0, page: 1, pageSize: 10 }));

    facade.retryFailed('t1');

    expect(gateway.loadTransactions).toHaveBeenCalled();
  });

  it('toggleFraudFlag sends the requested flag value, not its inverse', () => {
    gateway.setFraudFlag.and.returnValue(of(transaction()));
    gateway.loadTransactions.and.returnValue(of({ items: [], total: 0, page: 1, pageSize: 10 }));

    facade.toggleFraudFlag('t1', true);

    expect(gateway.setFraudFlag).toHaveBeenCalledWith('t1', true);
  });

  it('exportCsv emits one row per transaction plus a header', () => {
    gateway.loadTransactions.and.returnValue(of({ items: [transaction(), transaction({ id: 't2' })], total: 2, page: 1, pageSize: 10 }));
    facade.loadList();

    expect(facade.exportCsv().split('\n').length).toBe(3);
  });
});
