import { Injectable, computed, inject, signal } from '@angular/core';
import { take } from 'rxjs/operators';
import { AdminOrder, AdminOrderListFilters, AdminOrderStatus, TERMINAL_ORDER_STATUSES } from '../models/admin-order.model';
import { ADMIN_ORDERS_GATEWAY } from '../services/admin-orders-gateway.token';
import { LocalStorageService } from '../../../../core/storage/local-storage.service';

export type AdminOrdersViewMode = 'table' | 'cards';
export type AdminOrdersDensity = 'comfortable' | 'compact';

export const ALL_ORDER_COLUMNS = ['customer', 'status', 'payment', 'total', 'created'] as const;
export type AdminOrderColumn = typeof ALL_ORDER_COLUMNS[number];

export interface AdminOrdersDashboardStats {
  ordersToday: number;
  pending: number;
  paid: number;
  cancelled: number;
  refunded: number;
  customers: number;
  returningCustomers: number;
  averageOrder: number;
  currency: string;
  recentActivity: { orderNumber: string; orderId: string; eventKey: string; status: AdminOrderStatus; timestamp: string }[];
  alerts: { labelKey: string; count: number }[];
}

const VIEW_MODE_KEY = 'admin-orders:view-mode';
const DENSITY_KEY = 'admin-orders:density';
const COLUMNS_KEY = 'admin-orders:visible-columns';

@Injectable({ providedIn: 'root' })
export class AdminOrdersFacade {
  private readonly gateway = inject(ADMIN_ORDERS_GATEWAY);
  private readonly localStorage = inject(LocalStorageService);

  readonly filters = signal<AdminOrderListFilters>({ search: '', status: 'all', page: 1, pageSize: 10 });
  readonly orders = signal<AdminOrder[]>([]);
  readonly total = signal(0);
  readonly loading = signal(false);
  readonly error = signal<string | null>(null);
  readonly selected = signal<AdminOrder | null>(null);
  readonly selectedLoading = signal(false);
  readonly selectedError = signal<string | null>(null);

  readonly viewMode = signal<AdminOrdersViewMode>((this.localStorage.getItem(VIEW_MODE_KEY) as AdminOrdersViewMode) || 'table');
  readonly density = signal<AdminOrdersDensity>((this.localStorage.getItem(DENSITY_KEY) as AdminOrdersDensity) || 'comfortable');
  readonly visibleColumns = signal<AdminOrderColumn[]>(this.localStorage.getJSON<AdminOrderColumn[]>(COLUMNS_KEY) ?? [...ALL_ORDER_COLUMNS]);
  readonly selectedIds = signal<string[]>([]);
  readonly hasSelection = computed(() => this.selectedIds().length > 0);
  readonly dashboardStats = signal<AdminOrdersDashboardStats | null>(null);

  setViewMode(mode: AdminOrdersViewMode): void {
    this.viewMode.set(mode);
    this.localStorage.setItem(VIEW_MODE_KEY, mode);
  }

  setDensity(density: AdminOrdersDensity): void {
    this.density.set(density);
    this.localStorage.setItem(DENSITY_KEY, density);
  }

  setColumnVisible(column: AdminOrderColumn, visible: boolean): void {
    const next = visible ? [...new Set([...this.visibleColumns(), column])] : this.visibleColumns().filter(c => c !== column);
    this.visibleColumns.set(next);
    this.localStorage.setJSON(COLUMNS_KEY, next);
  }

  toggleSelection(id: string, checked: boolean): void {
    this.selectedIds.update(current => checked ? [...new Set([...current, id])] : current.filter(item => item !== id));
  }

  toggleAll(checked: boolean): void {
    this.selectedIds.set(checked ? this.orders().map(order => order.id) : []);
  }

  clearSelection(): void {
    this.selectedIds.set([]);
  }

  loadList(): void {
    this.loading.set(true);
    this.error.set(null);
    this.gateway.loadOrders(this.filters()).pipe(take(1)).subscribe({
      next: result => {
        this.orders.set(result.items);
        this.total.set(result.total);
        this.loading.set(false);
      },
      error: () => {
        this.orders.set([]);
        this.total.set(0);
        this.loading.set(false);
        this.error.set('common.errorDescription');
      }
    });
  }

  updateFilters(patch: Partial<AdminOrderListFilters>): void {
    this.filters.update(current => ({ ...current, ...patch, page: patch.page ?? 1 }));
    this.loadList();
  }

  loadDetail(id: string): void {
    this.selectedLoading.set(true);
    this.selectedError.set(null);
    this.gateway.loadOrder(id).pipe(take(1)).subscribe({
      next: order => {
        this.selected.set(order);
        this.selectedLoading.set(false);
      },
      error: () => {
        this.selectedLoading.set(false);
        this.selectedError.set('common.errorDescription');
      }
    });
  }

  setStatus(id: string, status: AdminOrderStatus): void {
    this.gateway.updateStatus(id, status).pipe(take(1)).subscribe({ next: order => this.selected.set(order) });
  }

  cancelOrder(id: string): void {
    this.setStatus(id, 'cancelled');
  }

  requestRefund(id: string): void {
    this.gateway.requestRefund(id).pipe(take(1)).subscribe({ next: order => this.selected.set(order) });
  }

  addNote(id: string, note: string, internal: boolean): void {
    if (!note.trim()) return;
    this.gateway.addNote(id, note.trim(), internal).pipe(take(1)).subscribe({ next: order => this.selected.set(order) });
  }

  applyBulkStatus(status: AdminOrderStatus): void {
    const ids = [...this.selectedIds()];
    ids.forEach(id => this.gateway.updateStatus(id, status).pipe(take(1)).subscribe());
    this.clearSelection();
    this.loadList();
    this.loadDashboardStats();
  }

  applyBulkArchive(archived: boolean): void {
    const ids = [...this.selectedIds()];
    ids.forEach(id => (archived ? this.gateway.archiveOrder(id) : this.gateway.restoreOrder(id)).pipe(take(1)).subscribe());
    this.clearSelection();
    this.loadList();
  }

  applyBulkDelete(): void {
    const ids = [...this.selectedIds()];
    ids.forEach(id => this.gateway.deleteOrder(id).pipe(take(1)).subscribe());
    this.clearSelection();
    this.loadList();
    this.loadDashboardStats();
  }

  exportCsv(): string {
    const header = 'Order Number,Status,Customer,Email,Total,Currency,Created At';
    const rows = this.orders().map(order =>
      [order.orderNumber, order.status, order.customer.name, order.customer.email, order.total, order.currency, order.createdAt].join(',')
    );
    return [header, ...rows].join('\n');
  }

  exportSelectedAsCsv(): void {
    const selected = new Set(this.selectedIds());
    const rows = this.orders().filter(order => selected.has(order.id));
    const header = 'Order Number,Status,Customer,Email,Total,Currency,Created At';
    const lines = rows.map(order => [order.orderNumber, order.status, order.customer.name, order.customer.email, order.total, order.currency, order.createdAt].join(','));
    const csv = [header, ...lines].join('\n');
    const blob = new Blob([csv], { type: 'text/csv' });
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.href = url;
    link.download = 'orders-export.csv';
    link.click();
    URL.revokeObjectURL(url);
  }

  /** Dashboard reflects the whole order book, not just the current filtered/paginated page. */
  loadDashboardStats(): void {
    this.gateway.loadOrders({ search: '', status: 'all', page: 1, pageSize: 100000 }).pipe(take(1))
      .subscribe({ next: result => this.dashboardStats.set(this.computeDashboardStats(result.items)) });
  }

  private computeDashboardStats(orders: AdminOrder[]): AdminOrdersDashboardStats {
    const startOfToday = new Date();
    startOfToday.setHours(0, 0, 0, 0);
    const ordersToday = orders.filter(order => new Date(order.createdAt) >= startOfToday).length;

    const byEmail = new Map<string, AdminOrder[]>();
    for (const order of orders) {
      const list = byEmail.get(order.customer.email) ?? [];
      list.push(order);
      byEmail.set(order.customer.email, list);
    }
    const returningCustomers = [...byEmail.values()].filter(list => list.length > 1).length;

    const total = orders.reduce((sum, order) => sum + order.total, 0);
    const averageOrder = orders.length > 0 ? Math.round(total / orders.length) : 0;

    const recentActivity = orders
      .flatMap(order => order.timeline.map(entry => ({ orderNumber: order.orderNumber, orderId: order.id, eventKey: entry.eventKey, status: entry.status, timestamp: entry.timestamp })))
      .sort((a, b) => b.timestamp.localeCompare(a.timestamp))
      .slice(0, 8);

    const stuckPending = orders.filter(order => order.status === 'pending' && Date.now() - new Date(order.createdAt).getTime() > 48 * 60 * 60 * 1000).length;
    const refundRequested = orders.filter(order => order.payment.status === 'refund_requested').length;
    const alerts: AdminOrdersDashboardStats['alerts'] = [
      ...(stuckPending > 0 ? [{ labelKey: 'adminOrders.alertStuckPending', count: stuckPending }] : []),
      ...(refundRequested > 0 ? [{ labelKey: 'adminOrders.alertRefundRequested', count: refundRequested }] : []),
    ];

    return {
      ordersToday,
      pending: orders.filter(order => order.status === 'pending').length,
      paid: orders.filter(order => order.payment.status === 'paid').length,
      cancelled: orders.filter(order => order.status === 'cancelled').length,
      refunded: orders.filter(order => order.status === 'refunded').length,
      customers: byEmail.size,
      returningCustomers,
      averageOrder,
      currency: orders[0]?.currency ?? '',
      recentActivity,
      alerts,
    };
  }
}
