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

const RESOURCE = 'Material%20Request';

export interface MaterialRequestItem {
  name?: string;
  item_code?: string;
  item_name?: string;
  description?: string;
  qty?: number;
  uom?: string;
  schedule_date?: string;
  idx?: number;
  [key: string]: any;
}

export interface MaterialRequest {
  name: string;
  docstatus?: number;
  status?: string;
  material_request_type?: string;
  transaction_date?: string;
  schedule_date?: string;
  company?: string;
  set_warehouse?: string;
  items?: MaterialRequestItem[];
  owner?: string;
  creation?: string;
  modified?: string;
  [key: string]: any;
}

class MaterialRequestService {
  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 headers = await this.getHeaders();
    const r = await fetch(url, { credentials: 'include', headers, ...opts });
    const body = await r.json().catch(() => ({}));
    if (!r.ok) throw new Error(formatFrappeApiError(body) || body?.message || `HTTP ${r.status}`);
    if (body.exc) throw new Error(formatFrappeApiError(body) || 'Request failed');
    return body;
  }

  async getMaterialRequests(
    params: { filters?: any[]; limit_start?: number; limit_page_length?: number; order_by?: string } = {},
  ): Promise<MaterialRequest[]> {
    const q = new URLSearchParams();
    const fields = [
      'name', 'material_request_type', 'transaction_date', 'status',
      'company', 'docstatus', 'creation', 'modified',
    ];
    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/${RESOURCE}?${q}`);
    return body.data || [];
  }

  async getMaterialRequestCount(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/${RESOURCE}?${q}`);
      return body.data?.[0]?.count ?? 0;
    } catch {
      return 0;
    }
  }

  async getMaterialRequest(name: string): Promise<MaterialRequest> {
    const body = await this.fetchJson(`/api/resource/${RESOURCE}/${encodeURIComponent(name)}`);
    return body.data;
  }

  async createMaterialRequest(data: Partial<MaterialRequest>): Promise<MaterialRequest> {
    const body = await this.fetchJson(`/api/resource/${RESOURCE}`, {
      method: 'POST',
      body: JSON.stringify(data),
    });
    return body.data;
  }

  async updateMaterialRequest(name: string, data: Partial<MaterialRequest>): Promise<MaterialRequest> {
    const body = await this.fetchJson(`/api/resource/${RESOURCE}/${encodeURIComponent(name)}`, {
      method: 'PUT',
      body: JSON.stringify(data),
    });
    return body.data;
  }

  async submitMaterialRequest(name: string): Promise<MaterialRequest> {
    const body = await this.fetchJson(`/api/resource/${RESOURCE}/${encodeURIComponent(name)}`, {
      method: 'PUT',
      body: JSON.stringify({ docstatus: 1 }),
    });
    return body.data;
  }
}

const materialRequestService = new MaterialRequestService();
export default materialRequestService;
