import { formatFrappeApiError } from '../utils/frappeErrorMessage';

export interface DeliveryNoteItem {
  name?: string; item_code?: string; item_name?: string; description?: string;
  qty?: number; uom?: string; stock_uom?: string; conversion_factor?: number;
  rate?: number; amount?: number; net_rate?: number; net_amount?: number;
  price_list_rate?: number; discount_percentage?: number;
  against_sales_order?: string; so_detail?: string;
  project?: string; cost_center?: string;
  is_free_item?: number; grant_commission?: number; idx?: number;
  [key: string]: any;
}

export interface DeliveryNote {
  name: string; docstatus?: number; owner?: string; creation?: string; modified?: string;
  naming_series?: string; posting_date?: string; posting_time?: string; set_posting_time?: number;
  customer?: string; customer_name?: string; company?: string;
  project?: string; cost_center?: string; currency?: string;
  selling_price_list?: string; status?: string; is_return?: number;
  items?: DeliveryNoteItem[]; taxes?: any[];
  grand_total?: number; net_total?: number; total?: number;
  total_taxes_and_charges?: number; rounded_total?: number; [key: string]: any;
}

class DeliveryNoteService {
  private async getCSRFToken(): Promise<string | null> {
    if (typeof window === 'undefined') return null;
    if ((window as any).csrf_token) return (window as any).csrf_token;
    if ((window as any).frappe?.csrf_token) return (window as any).frappe.csrf_token;
    try {
      const res = await fetch('/api/method/frappe.sessions.get_csrf_token', { credentials: 'include' });
      if (res.ok) { const json = await res.json(); if (json.message) { (window as any).csrf_token = json.message; return json.message; } }
    } catch { /* ignore */ }
    return null;
  }

  private async getHeaders(): Promise<Record<string, string>> {
    const h: Record<string, string> = { 'Content-Type': 'application/json', Accept: 'application/json' };
    const csrf = await this.getCSRFToken();
    if (csrf) h['X-Frappe-CSRF-Token'] = csrf;
    return h;
  }

  private async fetchJson(url: string, opts: RequestInit = {}): Promise<any> {
    const r = await fetch(url, { credentials: 'include', ...opts });
    const body = await r.json();
    if (!r.ok) {
      const msg = formatFrappeApiError(body) || body?.exc_type || `HTTP ${r.status}`;
      throw new Error(msg);
    }
    return body;
  }

  async getDeliveryNotes(params: { filters?: any[]; limit_start?: number; limit_page_length?: number; order_by?: string } = {}): Promise<DeliveryNote[]> {
    const q = new URLSearchParams();
    const fields = ['name','customer','customer_name','posting_date','status','grand_total','currency','docstatus','creation'];
    q.set('fields', JSON.stringify(fields));
    if (params.filters?.length) q.set('filters', JSON.stringify(params.filters));
    q.set('limit_start', String(params.limit_start ?? 0));
    q.set('limit_page_length', String(params.limit_page_length ?? 20));
    q.set('order_by', params.order_by ?? 'creation desc');
    const body = await this.fetchJson(`/api/resource/Delivery Note?${q}`);
    return body.data || [];
  }

  async getDeliveryNoteCount(filters: any[] = []): Promise<number> {
    const q = new URLSearchParams();
    q.set('fields', JSON.stringify(['count(name) as count']));
    if (filters.length) q.set('filters', JSON.stringify(filters));
    try {
      const body = await this.fetchJson(`/api/resource/Delivery Note?${q}`);
      return body.data?.[0]?.count ?? 0;
    } catch {
      return 0;
    }
  }

  async getDeliveryNote(name: string): Promise<DeliveryNote> {
    const body = await this.fetchJson(`/api/resource/Delivery Note/${encodeURIComponent(name)}`);
    return body.data;
  }

  async createDeliveryNote(data: Partial<DeliveryNote>): Promise<DeliveryNote> {
    const headers = await this.getHeaders();
    const body = await this.fetchJson('/api/resource/Delivery Note', { method: 'POST', headers, body: JSON.stringify({ ...data, doctype: 'Delivery Note' }) });
    return body.data;
  }

  async updateDeliveryNote(name: string, data: Partial<DeliveryNote>): Promise<DeliveryNote> {
    const headers = await this.getHeaders();
    const body = await this.fetchJson(`/api/resource/Delivery Note/${encodeURIComponent(name)}`, { method: 'PUT', headers, body: JSON.stringify(data) });
    return body.data;
  }

  async submitDeliveryNote(name: string): Promise<DeliveryNote> {
    const headers = await this.getHeaders();
    const body = await this.fetchJson(`/api/resource/Delivery Note/${encodeURIComponent(name)}`, { method: 'PUT', headers, body: JSON.stringify({ docstatus: 1 }) });
    return body.data;
  }
}

export default new DeliveryNoteService();
