/**
 * SentinelOne API Client
 * Covers: sites, agents, threats, groups
 * API version: 2.1
 */

export interface S1Site {
  id: string;
  accountId: string;
  accountName: string;
  name: string;
  siteType: string;
  state: string;
  sku: string;
  suite: string;
  healthStatus: boolean;
  activeLicenses: number;
  totalLicenses: number;
  unlimitedLicenses: boolean;
  unlimitedExpiration: boolean;
  expiration: string | null;
  isDefault: boolean;
  usageType: string;
  externalId: string | null;
  registrationToken: string | null;
  description: string | null;
  createdAt: string;
  updatedAt: string;
}

export interface S1Agent {
  id: string;
  siteId: string;
  siteName: string;
  accountId: string;
  accountName: string;
  groupId: string;
  groupName: string;
  computerName: string;
  domain: string | null;
  osType: string;
  osName: string;
  osRevision: string;
  agentVersion: string;
  machineType: string;
  isActive: boolean;
  isDecommissioned: boolean;
  isUpToDate: boolean;
  isPendingUninstall: boolean;
  isUninstalled: boolean;
  infected: boolean;
  activeThreats: number;
  networkStatus: string;
  mitigationMode: string;
  detectionState: string;
  appsVulnerabilityStatus: string;
  firewallEnabled: boolean;
  externalIp: string | null;
  lastActiveDate: string | null;
  lastLoggedInUserName: string | null;
  cpuId: string | null;
  coreCount: number | null;
  cpuCount: number | null;
  totalMemory: number | null;
  uuid: string;
  externalId: string | null;
  installerType: string | null;
  scanStatus: string | null;
  scanStartedAt: string | null;
  scanFinishedAt: string | null;
  createdAt: string;
  updatedAt: string;
}

export interface S1Threat {
  id: string;
  agentDetectionInfo: {
    siteId: string;
    siteName: string;
    accountId: string;
    agentUuid: string;
  };
  agentRealtimeInfo: {
    agentId: string;
    agentComputerName: string;
    agentOsName: string;
    agentVersion: string;
    agentIsActive: boolean;
    agentIsDecommissioned: boolean;
    siteId: string;
    siteName: string;
  };
  threatInfo: {
    threatName: string | null;
    filePath: string | null;
    sha256: string | null;
    classification: string | null;
    classificationSource: string | null;
    confidenceLevel: string | null;
    mitigationStatus: string | null;
    analystVerdict: string | null;
    incidentStatus: string | null;
    detectionEngines: any[] | null;
    createdAt: string;
    updatedAt: string;
  };
  mitigationStatus: any[];
  indicators: any[];
}

export interface S1Pagination {
  totalItems: number;
  nextCursor: string | null;
}

export interface S1ListResponse<T> {
  data: T[];
  pagination: S1Pagination;
}

export class SentinelOneClient {
  private baseUrl: string;
  private token: string;

  constructor(baseUrl?: string, token?: string) {
    this.baseUrl = (baseUrl || process.env.S1_API_URL || '').replace(/\/$/, '');
    this.token = token || process.env.S1_API_TOKEN || '';
    if (!this.baseUrl || !this.token) {
      throw new Error('SentinelOne: S1_API_URL and S1_API_TOKEN are required');
    }
  }

  private async request<T>(path: string, params: Record<string, string | number | boolean> = {}): Promise<T> {
    const url = new URL(`${this.baseUrl}${path}`);
    for (const [k, v] of Object.entries(params)) {
      if (v !== undefined && v !== null) url.searchParams.set(k, String(v));
    }

    const res = await fetch(url.toString(), {
      headers: {
        Authorization: `ApiToken ${this.token}`,
        'Content-Type': 'application/json',
      },
    });

    if (!res.ok) {
      const body = await res.text();
      throw new Error(`S1 API ${path} failed (${res.status}): ${body.slice(0, 200)}`);
    }

    return res.json();
  }

  private async getAllPages<T>(
    path: string,
    dataKey: string | null = null,
    extraParams: Record<string, string | number | boolean> = {}
  ): Promise<T[]> {
    const results: T[] = [];
    let cursor: string | null = null;

    do {
      const params: Record<string, string | number | boolean> = { limit: 1000, ...extraParams };
      if (cursor) params.cursor = cursor;

      const resp = await this.request<any>(path, params);
      const items = dataKey ? resp.data?.[dataKey] : resp.data;
      if (Array.isArray(items)) results.push(...items);

      cursor = resp.pagination?.nextCursor || null;
    } while (cursor);

    return results;
  }

  async testConnection(): Promise<{ ok: boolean; totalSites: number; totalAgents: number }> {
    const [sites, agents] = await Promise.all([
      this.request<any>('/web/api/v2.1/sites?limit=1&countOnly=false'),
      this.request<any>('/web/api/v2.1/agents?limit=1&countOnly=false'),
    ]);
    return {
      ok: true,
      totalSites: sites.pagination?.totalItems ?? 0,
      totalAgents: agents.pagination?.totalItems ?? 0,
    };
  }

  async getSites(): Promise<S1Site[]> {
    return this.getAllPages<S1Site>('/web/api/v2.1/sites', 'sites');
  }

  async getAgents(siteId?: string): Promise<S1Agent[]> {
    const extra: Record<string, string | number | boolean> = siteId ? { siteIds: siteId } : {};
    return this.getAllPages<S1Agent>('/web/api/v2.1/agents', null, extra);
  }

  async getThreats(siteId?: string): Promise<S1Threat[]> {
    const extra: Record<string, string | number | boolean> = siteId ? { siteIds: siteId } : {};
    return this.getAllPages<S1Threat>('/web/api/v2.1/threats', null, extra);
  }

  async getSiteSummary(siteId: string): Promise<{
    agents: number;
    activeAgents: number;
    infected: number;
    upToDate: number;
    threats: number;
  }> {
    const [agentsResp, threatsResp] = await Promise.all([
      this.request<any>('/web/api/v2.1/agents', { siteIds: siteId, countOnly: false, limit: 1 }),
      this.request<any>('/web/api/v2.1/threats', { siteIds: siteId, countOnly: false, limit: 1 }),
    ]);

    const [activeResp, infectedResp, upToDateResp] = await Promise.all([
      this.request<any>('/web/api/v2.1/agents', { siteIds: siteId, isActive: true, countOnly: true }),
      this.request<any>('/web/api/v2.1/agents', { siteIds: siteId, infected: true, countOnly: true }),
      this.request<any>('/web/api/v2.1/agents', { siteIds: siteId, isUpToDate: true, countOnly: true }),
    ]);

    return {
      agents: agentsResp.pagination?.totalItems ?? 0,
      activeAgents: activeResp.data?.totalItems ?? 0,
      infected: infectedResp.data?.totalItems ?? 0,
      upToDate: upToDateResp.data?.totalItems ?? 0,
      threats: threatsResp.pagination?.totalItems ?? 0,
    };
  }
}

let _client: SentinelOneClient | null = null;
export function getSentinelOneClient(): SentinelOneClient {
  if (!_client) _client = new SentinelOneClient();
  return _client;
}
