import API_CONFIG from '../config/api';
import { toFrappeFilterArray } from '../utils/listFilterUtils';

// ─── Customer ─────────────────────────────────────────────────────────────────
export interface Customer {
  name: string;
  naming_series?: string;
  customer_name?: string;
  customer_type?: string;       // Company | Individual | Hospital
  customer_group?: string;
  territory?: string;
  is_internal_customer?: number;
  language?: string;
  default_commission_rate?: number;
  so_required?: number;
  dn_required?: number;
  is_frozen?: number;
  disabled?: number;
  owner?: string;
  creation?: string;
  modified?: string;
  docstatus?: number;
  [key: string]: any;
}

// ─── Employee ─────────────────────────────────────────────────────────────────
export interface Employee {
  name: string;
  naming_series?: string;
  employee_name?: string;
  first_name?: string;
  middle_name?: string;
  last_name?: string;
  salutation?: string;
  gender?: string;
  date_of_birth?: string;
  date_of_joining?: string;
  status?: string;              // Active | Inactive | Left | On Leave
  // Company Details section
  company?: string;             // Labeled "Hospital" in this system
  designation?: string;
  branch?: string;
  department?: string;
  reports_to?: string;
  employee_number?: string;
  user_id?: string;
  owner?: string;
  creation?: string;
  modified?: string;
  docstatus?: number;
  [key: string]: any;
}

// ─── Service ──────────────────────────────────────────────────────────────────
class MasterService {
  private readonly baseURL = API_CONFIG.BASE_URL;

  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(`${this.baseURL}/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> = { Accept: 'application/json', 'Content-Type': 'application/json' };
    const csrf = await this.getCSRFToken();
    if (csrf) h['X-Frappe-CSRF-Token'] = csrf;
    return h;
  }

  private async parseFrappeError(response: Response): Promise<Error> {
    try {
      const body = await response.json();
      if (body._server_messages) {
        try {
          const msgs = JSON.parse(body._server_messages);
          const parsed = typeof msgs[0] === 'string' ? JSON.parse(msgs[0]) : msgs[0];
          if (parsed?.message) return new Error(parsed.message);
        } catch { /* ignore */ }
      }
      if (body.message && typeof body.message === 'string') return new Error(body.message);
      if (body.exc_type) return new Error(`${body.exc_type}: ${body.exc?.split('\n').slice(-2).join(' ').trim() || response.statusText}`);
    } catch { /* ignore */ }
    const map: Record<number, string> = { 403: 'Permission denied.', 404: 'Record not found.', 417: 'Validation error.', 500: 'Server error.' };
    return new Error(map[response.status] || `HTTP ${response.status}`);
  }

  private async fetchJson(url: string, options?: RequestInit): Promise<any> {
    const response = await fetch(url, {
      credentials: 'include', ...options,
      headers: { ...await this.getHeaders(), ...(options?.headers || {}) },
    });
    if (!response.ok) throw await this.parseFrappeError(response.clone());
    return response.json();
  }

  // ─── Customer ───────────────────────────────────────────────────────────────
  async getCustomers(params: { limit_start?: number; limit_page_length?: number; filters?: Record<string, any> } = {}): Promise<{ data: Customer[] }> {
    const { limit_start = 0, limit_page_length = 20, filters = {} } = params;
    const q = new URLSearchParams();
    q.set('fields', JSON.stringify(['name','customer_name','customer_type','customer_group','territory','disabled','creation','modified']));
    q.set('limit_start', String(limit_start));
    q.set('limit_page_length', String(limit_page_length));
    q.set('order_by', 'modified desc');
    if (Object.keys(filters).length > 0) {
      const fa = toFrappeFilterArray(filters);
      if (fa.length > 0) q.set('filters', JSON.stringify(fa));
    }
    const r = await this.fetchJson(`${this.baseURL}/api/resource/Customer?${q}`);
    return { data: r.data || [] };
  }

  async getCustomer(name: string): Promise<Customer> {
    const r = await this.fetchJson(`${this.baseURL}/api/resource/Customer/${encodeURIComponent(name)}`);
    return r.data;
  }

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

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

  async getCustomerCount(filters: Record<string, any> = {}): Promise<number> {
    const q = new URLSearchParams();
    q.set('fields', JSON.stringify(['count(name) as count']));
    if (Object.keys(filters).length > 0) {
      const fa = toFrappeFilterArray(filters);
      if (fa.length > 0) q.set('filters', JSON.stringify(fa));
    }
    try { const r = await this.fetchJson(`${this.baseURL}/api/resource/Customer?${q}`); return r.data?.[0]?.count || 0; } catch { return 0; }
  }

  // ─── Employee ───────────────────────────────────────────────────────────────
  async getEmployees(params: { limit_start?: number; limit_page_length?: number; filters?: Record<string, any> } = {}): Promise<{ data: Employee[] }> {
    const { limit_start = 0, limit_page_length = 20, filters = {} } = params;
    const q = new URLSearchParams();
    q.set('fields', JSON.stringify(['name','employee_name','first_name','last_name','gender','status','company','designation','department','date_of_joining','creation','modified']));
    q.set('limit_start', String(limit_start));
    q.set('limit_page_length', String(limit_page_length));
    q.set('order_by', 'modified desc');
    if (Object.keys(filters).length > 0) {
      const fa = toFrappeFilterArray(filters);
      if (fa.length > 0) q.set('filters', JSON.stringify(fa));
    }
    const r = await this.fetchJson(`${this.baseURL}/api/resource/Employee?${q}`);
    return { data: r.data || [] };
  }

  async getEmployee(name: string): Promise<Employee> {
    const r = await this.fetchJson(`${this.baseURL}/api/resource/Employee/${encodeURIComponent(name)}`);
    return r.data;
  }

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

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

  async getEmployeeCount(filters: Record<string, any> = {}): Promise<number> {
    const q = new URLSearchParams();
    q.set('fields', JSON.stringify(['count(name) as count']));
    if (Object.keys(filters).length > 0) {
      const fa = toFrappeFilterArray(filters);
      if (fa.length > 0) q.set('filters', JSON.stringify(fa));
    }
    try { const r = await this.fetchJson(`${this.baseURL}/api/resource/Employee?${q}`); return r.data?.[0]?.count || 0; } catch { return 0; }
  }
}

const masterService = new MasterService();
export default masterService;
