import { Injectable, inject } from '@angular/core';
import { Observable, of } from 'rxjs';
import { delay } from 'rxjs/operators';
import { AdminOrder, AdminOrderListFilters, AdminOrdersListResult, AdminOrderStatus, TERMINAL_ORDER_STATUSES } from '../models/admin-order.model';
import { AdminOrdersGateway } from './admin-orders-gateway.interface';
import { AdminAuthService } from '@marketplaces/auth';

const STATUSES: AdminOrderStatus[] = ['pending', 'processing', 'shipped', 'delivered', 'cancelled', 'refunded'];
const CUSTOMER_NAMES = ['Anna Petrova', 'Karen Sargsyan', 'Ivan Ivanov', 'Mariam Grigoryan', 'Sergey Volkov', 'Lilit Hakobyan'];
const SEED_COUNT = 24;

@Injectable({ providedIn: 'root' })
export class AdminOrdersLocalGateway implements AdminOrdersGateway {
  private readonly adminAuth = inject(AdminAuthService);
  private cache: AdminOrder[] | null = null;

  private get currentActor(): string {
    return this.adminAuth.displayName() ?? 'admin';
  }

  loadOrders(filters: AdminOrderListFilters): Observable<AdminOrdersListResult> {
    const all = this.ensureData();
    const filtered = all
      .filter(order => !filters.search || `${order.orderNumber} ${order.customer.name} ${order.customer.email}`.toLowerCase().includes(filters.search.toLowerCase()))
      .filter(order => filters.status === 'all' || order.status === filters.status)
      .sort((left, right) => right.createdAt.localeCompare(left.createdAt));
    const start = (filters.page - 1) * filters.pageSize;
    return of({
      items: filtered.slice(start, start + filters.pageSize),
      total: filtered.length,
      page: filters.page,
      pageSize: filters.pageSize,
    }).pipe(delay(50));
  }

  loadOrder(id: string): Observable<AdminOrder | null> {
    return of(this.ensureData().find(order => order.id === id) ?? null).pipe(delay(50));
  }

  updateStatus(id: string, status: AdminOrderStatus): Observable<AdminOrder | null> {
    return this.mutate(id, order => {
      // Once terminal (cancelled/refunded), an order never moves to any
      // other status again - enforced here, not just in the admin UI, so
      // no caller (this gateway is the single write path) can reopen one.
      if (TERMINAL_ORDER_STATUSES.includes(order.status)) {
        return order;
      }
      return {
        ...order,
        status,
        updatedAt: new Date().toISOString(),
        timeline: [...order.timeline, { status, timestamp: new Date().toISOString(), eventKey: 'statusChanged' as const, actor: this.currentActor }],
      };
    });
  }

  requestRefund(id: string): Observable<AdminOrder | null> {
    return this.mutate(id, order => ({
      ...order,
      payment: { ...order.payment, status: 'refund_requested' },
      updatedAt: new Date().toISOString(),
      timeline: [...order.timeline, { status: order.status, timestamp: new Date().toISOString(), eventKey: 'refundRequested' as const, actor: this.currentActor }],
    }));
  }

  addNote(id: string, note: string, internal: boolean): Observable<AdminOrder | null> {
    return this.mutate(id, order => ({
      ...order,
      notes: internal ? order.notes : order.notes ? `${order.notes}\n${note}` : note,
      internalNotes: internal ? (order.internalNotes ? `${order.internalNotes}\n${note}` : note) : order.internalNotes,
      updatedAt: new Date().toISOString(),
    }));
  }

  archiveOrder(id: string): Observable<AdminOrder | null> {
    return this.mutate(id, order => ({ ...order, archived: true, updatedAt: new Date().toISOString() }));
  }

  restoreOrder(id: string): Observable<AdminOrder | null> {
    return this.mutate(id, order => ({ ...order, archived: false, updatedAt: new Date().toISOString() }));
  }

  deleteOrder(id: string): Observable<void> {
    this.cache = this.ensureData().filter(order => order.id !== id);
    return of(void 0).pipe(delay(50));
  }

  private mutate(id: string, update: (order: AdminOrder) => AdminOrder): Observable<AdminOrder | null> {
    const all = this.ensureData();
    const existing = all.find(order => order.id === id);
    if (!existing) {
      return of(null);
    }
    const updated = update(existing);
    this.cache = all.map(order => order.id === id ? updated : order);
    return of(updated).pipe(delay(50));
  }

  private ensureData(): AdminOrder[] {
    if (!this.cache) {
      this.cache = Array.from({ length: SEED_COUNT }, (_, index) => this.seedOrder(index));
    }
    return this.cache;
  }

  private seedOrder(index: number): AdminOrder {
    const status = STATUSES[index % STATUSES.length];
    const customerName = CUSTOMER_NAMES[index % CUSTOMER_NAMES.length];
    const total = 1500 + (index * 137) % 8000;
    const createdAt = new Date(Date.now() - index * 36 * 60 * 60 * 1000).toISOString();
    return {
      id: `order-${index + 1}`,
      orderNumber: `ORD-${1000 + index}`,
      status,
      customer: {
        name: customerName,
        email: `${customerName.toLowerCase().replace(/\s+/g, '.')}@example.com`,
        phone: `+374${90000000 + index}`,
      },
      payment: {
        method: index % 2 === 0 ? 'card' : 'cash_on_delivery',
        status: status === 'cancelled' ? 'refunded' : status === 'delivered' ? 'paid' : 'unpaid',
        amount: total,
        currency: 'RUB',
      },
      shipping: {
        address: `Sample Street ${index + 1}, Yerevan`,
        method: index % 3 === 0 ? 'courier' : 'pickup',
        trackingNumber: status === 'shipped' || status === 'delivered' ? `TRACK-${100000 + index}` : '',
      },
      items: [
        { productId: `product-${(index % 5) + 1}`, name: `Sample Product ${(index % 5) + 1}`, quantity: 1 + (index % 3), price: Math.round(total / (1 + (index % 3))) },
      ],
      total,
      currency: 'RUB',
      notes: '',
      internalNotes: '',
      timeline: [
        { status: 'pending', timestamp: createdAt, eventKey: 'created', actor: 'system' },
        ...(status !== 'pending' ? [{ status, timestamp: createdAt, eventKey: 'statusChanged' as const, actor: 'system' }] : []),
      ],
      archived: false,
      createdAt,
      updatedAt: createdAt,
    };
  }
}
