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

const RESOURCE = 'Project%20Update';

/** Child row on Project Update (Project User) */
export interface ProjectUpdateUserRow {
  name?: string;
  user?: string;
  email?: string;
  full_name?: string;
  welcome_email_sent?: number;
  view_attachments?: number;
  hide_timesheets?: number;
  idx?: number;
  [key: string]: any;
}

export interface ProjectUpdate {
  name: string;
  project?: string;
  sent?: number;
  date?: string;
  time?: string;
  users?: ProjectUpdateUserRow[];
  owner?: string;
  creation?: string;
  modified?: string;
  modified_by?: string;
  docstatus?: number;
  naming_series?: string;
  [key: string]: any;
}

class ProjectUpdateService {
  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 getProjectUpdates(params: {
    filters?: Record<string, any>;
    fields?: string[];
    limit_start?: number;
    limit_page_length?: number;
    order_by?: string;
  } = {}): Promise<ProjectUpdate[]> {
    const {
      filters = {},
      fields = ['name', 'project', 'sent', 'date', 'time', 'docstatus', 'owner', 'creation', 'modified'],
      limit_start = 0,
      limit_page_length = 20,
      order_by = 'creation desc',
    } = params;
    const q = new URLSearchParams();
    q.set('fields', JSON.stringify(fields));
    const fa = toFrappeFilterArray(filters);
    if (fa.length) q.set('filters', JSON.stringify(fa));
    q.set('limit_start', String(limit_start));
    q.set('limit_page_length', String(limit_page_length));
    q.set('order_by', order_by);
    const body = await this.fetchJson(`/api/resource/${RESOURCE}?${q}`);
    return body.data || [];
  }

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

  async getProjectUpdate(name: string): Promise<ProjectUpdate> {
    // Request full document so child table fields (email/full_name/flags) are included.
    const q = new URLSearchParams();
    q.set('fields', JSON.stringify(['*']));
    const body = await this.fetchJson(`/api/resource/${RESOURCE}/${encodeURIComponent(name)}?${q}`);
    return body.data;
  }

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

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

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

const projectUpdateService = new ProjectUpdateService();
export default projectUpdateService;
