import { TestBed } from '@angular/core/testing';
import { of, throwError } from 'rxjs';
import { AdminModerationFacade } from './admin-moderation.facade';
import { ADMIN_MODERATION_GATEWAY } from '../services/admin-moderation-gateway.token';
import { AdminModerationGateway } from '../services/admin-moderation-gateway.interface';
import { AdminReview } from '../models/admin-review.model';
import { LocalStorageService } from '../../../../core/storage/local-storage.service';

function review(overrides: Partial<AdminReview> = {}): AdminReview {
  return {
    id: 'r1',
    productId: 'p1',
    productName: 'Widget',
    customerName: 'Buyer',
    customerEmail: 'b@example.com',
    rating: 5,
    text: 'Great',
    photos: [],
    status: 'pending',
    visible: true,
    pinned: false,
    featured: false,
    reportCount: 0,
    moderatorNotes: '',
    timeline: [],
    createdAt: new Date().toISOString(),
    updatedAt: new Date().toISOString(),
    ...overrides,
  };
}

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

  beforeEach(() => {
    gateway = jasmine.createSpyObj<AdminModerationGateway>('AdminModerationGateway', [
      'loadReviews', 'loadReview', 'setReviewStatus', 'setReviewVisible', 'setReviewPinned',
      'setReviewFeatured', 'addModeratorNote', 'deleteReview', 'loadReports', 'setReportStatus',
    ]);

    TestBed.configureTestingModule({
      providers: [
        { provide: ADMIN_MODERATION_GATEWAY, useValue: gateway },
        { provide: LocalStorageService, useValue: { getItem: () => null, setItem: () => {}, getJSON: () => null, setJSON: () => {} } },
      ],
    });

    facade = TestBed.inject(AdminModerationFacade);
  });

  describe('health', () => {
    it('scores 100% when every check passes', () => {
      const result = facade.health(review({ rating: 5, text: 'x', photos: ['a'], status: 'approved', reportCount: 0, visible: true }));

      expect(result.completionPercent).toBe(100);
    });

    it('scores 0% when every check fails', () => {
      const result = facade.health(review({ rating: 0, text: '', photos: [], status: 'pending', reportCount: 1, visible: false }));

      expect(result.completionPercent).toBe(0);
    });

    it('treats whitespace-only text as no text', () => {
      const result = facade.health(review({ text: '   ' }));

      expect(result.hasText).toBeFalse();
    });

    it('any status other than pending counts as moderated', () => {
      expect(facade.health(review({ status: 'approved' })).isModerated).toBeTrue();
      expect(facade.health(review({ status: 'rejected' })).isModerated).toBeTrue();
      expect(facade.health(review({ status: 'pending' })).isModerated).toBeFalse();
    });
  });

  describe('loadDashboardStats', () => {
    it('computes averageRating only from reviews that have a rating', () => {
      gateway.loadReviews.and.returnValue(of({
        items: [review({ rating: 4 }), review({ rating: 0 }), review({ rating: 5 })],
        total: 3, page: 1, pageSize: 100000,
      }));

      facade.loadDashboardStats();

      // (4 + 5) / 2 = 4.5 - the zero-rating review must not drag the average down.
      expect(facade.dashboardStats()?.averageRating).toBe(4.5);
    });

    it('averageRating is null when no review has a rating, not 0', () => {
      gateway.loadReviews.and.returnValue(of({
        items: [review({ rating: 0 })],
        total: 1, page: 1, pageSize: 100000,
      }));

      facade.loadDashboardStats();

      expect(facade.dashboardStats()?.averageRating).toBeNull();
    });

    it('moderationHealthPercent is 100 for an empty queue, not a divide-by-zero artifact', () => {
      gateway.loadReviews.and.returnValue(of({ items: [], total: 0, page: 1, pageSize: 100000 }));

      facade.loadDashboardStats();

      expect(facade.dashboardStats()?.moderationHealthPercent).toBe(100);
    });

    it('counts reported reviews independently of their moderation status', () => {
      gateway.loadReviews.and.returnValue(of({
        items: [review({ status: 'approved', reportCount: 2 }), review({ status: 'pending', reportCount: 0 })],
        total: 2, page: 1, pageSize: 100000,
      }));

      facade.loadDashboardStats();

      expect(facade.dashboardStats()?.reported).toBe(1);
    });
  });

  describe('setReportStatus', () => {
    it('reloads the reports list after a successful status change', () => {
      gateway.setReportStatus.and.returnValue(of(null));
      gateway.loadReports.and.returnValue(of([]));

      facade.setReportStatus('rep1', 'resolved');

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

  describe('loadReports error handling', () => {
    it('clears reports and sets reportsError on failure', () => {
      gateway.loadReports.and.returnValue(throwError(() => new Error('x')));

      facade.loadReports();

      expect(facade.reports()).toEqual([]);
      expect(facade.reportsError()).toBeTrue();
      expect(facade.reportsLoading()).toBeFalse();
    });
  });

  describe('selection', () => {
    it('toggleAll selects every loaded review id', () => {
      gateway.loadReviews.and.returnValue(of({ items: [review({ id: 'a' }), review({ id: 'b' })], total: 2, page: 1, pageSize: 10 }));
      facade.loadList();

      facade.toggleAll(true);

      expect(facade.selectedIds()).toEqual(['a', 'b']);
    });
  });
});
