// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

import { APIResource } from '../../../core/resource';
import { APIPromise } from '../../../core/api-promise';
import {
  CursorLimitPagination,
  type CursorLimitPaginationParams,
  PagePromise,
} from '../../../core/pagination';
import { buildHeaders } from '../../../internal/headers';
import { RequestOptions } from '../../../internal/request-options';
import { path } from '../../../internal/utils/path';

export class BaseScans extends APIResource {
  static override readonly _key: readonly ['managedDefense', 'vulnerabilityDiscovery', 'scans'] =
    Object.freeze(['managedDefense', 'vulnerabilityDiscovery', 'scans'] as const);

  /**
   * Submits repository intent for operator review. This endpoint does not
   * immediately start execution. Worker-imported repositories must be ready;
   * explicit `repo_hosts` must be authorized before the request is persisted.
   *
   * @example
   * ```ts
   * const scan =
   *   await client.managedDefense.vulnerabilityDiscovery.scans.create(
   *     {
   *       account_id: '023e105f4ecef8ad9ca31a8372d0c353',
   *       repos: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'],
   *     },
   *   );
   * ```
   */
  create(params: ScanCreateParams, options?: RequestOptions): APIPromise<ScanCreateResponse> {
    const { account_id, 'Idempotency-Key': idempotencyKey, ...body } = params;
    return (
      this._client.post(path`/accounts/${account_id}/managed-defense/vulnerability-discovery/scans`, {
        body,
        ...options,
        headers: buildHeaders([
          { ...(idempotencyKey != null ? { 'Idempotency-Key': idempotencyKey } : undefined) },
          options?.headers,
        ]),
      }) as APIPromise<{ result: ScanCreateResponse }>
    )._thenUnwrap((obj) => obj.result);
  }

  /**
   * Lists customer-requested scans across review and execution lifecycle states.
   *
   * @example
   * ```ts
   * // Automatically fetches more pages as needed.
   * for await (const scanListResponse of client.managedDefense.vulnerabilityDiscovery.scans.list(
   *   { account_id: '023e105f4ecef8ad9ca31a8372d0c353' },
   * )) {
   *   // ...
   * }
   * ```
   */
  list(
    params: ScanListParams,
    options?: RequestOptions,
  ): PagePromise<ScanListResponsesCursorLimitPagination, ScanListResponse> {
    const { account_id, ...query } = params;
    return this._client.getAPIList(
      path`/accounts/${account_id}/managed-defense/vulnerability-discovery/scans`,
      CursorLimitPagination<ScanListResponse>,
      { query, ...options },
    );
  }

  /**
   * Gets one customer-requested scan across its review and execution lifecycle.
   *
   * @example
   * ```ts
   * const scan =
   *   await client.managedDefense.vulnerabilityDiscovery.scans.get(
   *     '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',
   *     { account_id: '023e105f4ecef8ad9ca31a8372d0c353' },
   *   );
   * ```
   */
  get(scanID: string, params: ScanGetParams, options?: RequestOptions): APIPromise<ScanGetResponse> {
    const { account_id } = params;
    return (
      this._client.get(
        path`/accounts/${account_id}/managed-defense/vulnerability-discovery/scans/${scanID}`,
        options,
      ) as APIPromise<{ result: ScanGetResponse }>
    )._thenUnwrap((obj) => obj.result);
  }

  /**
   * Gets the active operator-reviewed scan report. Repository metadata records
   * report readiness even when no publication is available.
   *
   * @example
   * ```ts
   * const response =
   *   await client.managedDefense.vulnerabilityDiscovery.scans.getReport(
   *     '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',
   *     { account_id: '023e105f4ecef8ad9ca31a8372d0c353' },
   *   );
   * ```
   */
  getReport(
    scanID: string,
    params: ScanGetReportParams,
    options?: RequestOptions,
  ): APIPromise<ScanGetReportResponse> {
    const { account_id } = params;
    return (
      this._client.get(
        path`/accounts/${account_id}/managed-defense/vulnerability-discovery/scans/${scanID}/report`,
        options,
      ) as APIPromise<{ result: ScanGetReportResponse }>
    )._thenUnwrap((obj) => obj.result);
  }
}
export class Scans extends BaseScans {}

export type ScanListResponsesCursorLimitPagination = CursorLimitPagination<ScanListResponse>;

export interface ScanCreateResponse {
  id: string;

  completed_at: string | null;

  message: string | null;

  phase: 'provisioning' | 'indexing' | 'analyzing' | 'reporting' | 'finalizing' | null;

  repositories: Array<ScanCreateResponse.Repository>;

  started_at: string | null;

  status: 'requested' | 'accepted' | 'running' | 'completed' | 'failed' | 'rejected' | 'cancelled';

  submitted_at: string;

  /**
   * UTC ISO-8601 interval. Start is inclusive, end is exclusive, and the interval
   * must be positive and at most seven days.
   */
  telemetry_window?: ScanCreateResponse.TelemetryWindow;
}

export namespace ScanCreateResponse {
  export interface Repository {
    id: string;

    name: string;

    phase: 'provisioning' | 'indexing' | 'analyzing' | 'reporting' | 'finalizing' | null;

    report_status: 'not_ready' | 'pending_review' | 'published' | 'withdrawn';

    status: 'requested' | 'accepted' | 'running' | 'completed' | 'failed' | 'rejected' | 'cancelled';
  }

  /**
   * UTC ISO-8601 interval. Start is inclusive, end is exclusive, and the interval
   * must be positive and at most seven days.
   */
  export interface TelemetryWindow {
    end: string;

    start: string;
  }
}

export interface ScanListResponse {
  id: string;

  completed_at: string | null;

  message: string | null;

  phase: 'provisioning' | 'indexing' | 'analyzing' | 'reporting' | 'finalizing' | null;

  repositories: Array<ScanListResponse.Repository>;

  started_at: string | null;

  status: 'requested' | 'accepted' | 'running' | 'completed' | 'failed' | 'rejected' | 'cancelled';

  submitted_at: string;

  /**
   * UTC ISO-8601 interval. Start is inclusive, end is exclusive, and the interval
   * must be positive and at most seven days.
   */
  telemetry_window?: ScanListResponse.TelemetryWindow;
}

export namespace ScanListResponse {
  export interface Repository {
    id: string;

    name: string;

    phase: 'provisioning' | 'indexing' | 'analyzing' | 'reporting' | 'finalizing' | null;

    report_status: 'not_ready' | 'pending_review' | 'published' | 'withdrawn';

    status: 'requested' | 'accepted' | 'running' | 'completed' | 'failed' | 'rejected' | 'cancelled';
  }

  /**
   * UTC ISO-8601 interval. Start is inclusive, end is exclusive, and the interval
   * must be positive and at most seven days.
   */
  export interface TelemetryWindow {
    end: string;

    start: string;
  }
}

export interface ScanGetResponse {
  id: string;

  completed_at: string | null;

  message: string | null;

  phase: 'provisioning' | 'indexing' | 'analyzing' | 'reporting' | 'finalizing' | null;

  repositories: Array<ScanGetResponse.Repository>;

  started_at: string | null;

  status: 'requested' | 'accepted' | 'running' | 'completed' | 'failed' | 'rejected' | 'cancelled';

  submitted_at: string;

  /**
   * UTC ISO-8601 interval. Start is inclusive, end is exclusive, and the interval
   * must be positive and at most seven days.
   */
  telemetry_window?: ScanGetResponse.TelemetryWindow;
}

export namespace ScanGetResponse {
  export interface Repository {
    id: string;

    name: string;

    phase: 'provisioning' | 'indexing' | 'analyzing' | 'reporting' | 'finalizing' | null;

    report_status: 'not_ready' | 'pending_review' | 'published' | 'withdrawn';

    status: 'requested' | 'accepted' | 'running' | 'completed' | 'failed' | 'rejected' | 'cancelled';
  }

  /**
   * UTC ISO-8601 interval. Start is inclusive, end is exclusive, and the interval
   * must be positive and at most seven days.
   */
  export interface TelemetryWindow {
    end: string;

    start: string;
  }
}

export interface ScanGetReportResponse {
  publication: ScanGetReportResponse.Publication | null;

  report: ScanGetReportResponse.Report | null;

  repositories: Array<ScanGetReportResponse.Repository>;

  scan_id: string;
}

export namespace ScanGetReportResponse {
  export interface Publication {
    published_at: string;

    revision_id: string;

    version: number;
  }

  export interface Report {
    executive_summary: string;

    /**
     * Revision requests must echo the existing generation timestamp unchanged.
     */
    generated_at: string;

    overall_severity: 'critical' | 'high' | 'medium' | 'low' | 'info';

    repositories: Array<Report.Repository>;

    schema_version: 2;

    title: string;
  }

  export namespace Report {
    export interface Repository {
      findings: Array<Repository.Finding>;

      overall_severity: 'critical' | 'high' | 'medium' | 'low' | 'info';

      repository_id: string;

      repository_name: string;

      summary: string;

      traffic_context: Repository.TrafficContext;

      external_links?: Array<Repository.ExternalLink>;

      limitations?: Array<string>;
    }

    export namespace Repository {
      export interface Finding {
        id: string;

        conditions: Array<string>;

        cwe: string;

        impact: string;

        location: Finding.Location;

        reachability: Array<Finding.Reachability>;

        remediation: Finding.Remediation;

        root_cause: string;

        severity: 'critical' | 'high' | 'medium' | 'low' | 'info';

        severity_basis: string;

        summary: string;

        telemetry: Finding.Telemetry;

        title: string;

        trace: Array<Finding.Trace>;

        waf_rules: Finding.WAFRules | null;

        /**
         * Least-privileged position required to trigger the finding. Optional on legacy
         * report revisions.
         */
        attacker_position?: 'external' | 'authenticated' | 'internal' | 'post_compromise' | null;

        external_links?: Array<Finding.ExternalLink>;

        /**
         * One bounded unresolved proof question. Optional on legacy report revisions.
         */
        open_question?: string | null;

        /**
         * Method used or needed to close the proof. Optional on legacy report revisions.
         */
        proof_method?:
          | 'structural'
          | 'experimental'
          | 'acquired_source'
          | 'public_knowledge'
          | 'team_question'
          | null;

        /**
         * Current proof lifecycle state. Optional on legacy report revisions.
         */
        proof_state?:
          | 'closed'
          | 'pending_source'
          | 'pending_public'
          | 'pending_experiment'
          | 'pending_team'
          | null;
      }

      export namespace Finding {
        export interface Location {
          file: string;

          line: number;

          route: string | null;
        }

        export interface Reachability {
          consumer: string;

          reachable: boolean;

          via: string;
        }

        export interface Remediation {
          code_changes: string | null;

          strategy: string;
        }

        export interface Telemetry {
          references: Array<string>;

          state: 'no_route' | 'no_telemetry' | 'no_match' | 'matched';
        }

        export interface Trace {
          line: number;

          path: string;

          scope: string;

          why: string;
        }

        export interface WAFRules {
          broad: WAFRules.Broad | null;

          targeted: WAFRules.Targeted | null;
        }

        export namespace WAFRules {
          export interface Broad {
            action: 'block' | 'managed_challenge' | 'js_challenge' | 'log';

            confidence: 'low' | 'medium' | 'high';

            description: string;

            expression: string;

            false_positive_risk: string;

            name: string;

            rationale: string;
          }

          export interface Targeted {
            action: 'block' | 'managed_challenge' | 'js_challenge' | 'log';

            confidence: 'low' | 'medium' | 'high';

            description: string;

            expression: string;

            false_positive_risk: string;

            name: string;

            rationale: string;
          }
        }

        export interface ExternalLink {
          title: string;

          url: string;
        }
      }

      export interface TrafficContext {
        http: TrafficContext.HTTP | null;

        target: TrafficContext.Target | null;

        waf: TrafficContext.WAF | null;

        web_assets: TrafficContext.WebAssets | null;
      }

      export namespace TrafficContext {
        export interface HTTP {
          error_paths: Array<HTTP.ErrorPath>;

          hot_paths: Array<HTTP.HotPath>;

          request_volume: number;
        }

        export namespace HTTP {
          export interface ErrorPath {
            id: string;

            hits: number;

            host: string;

            path: string;

            status: number;
          }

          export interface HotPath {
            id: string;

            hits: number;

            host: string;

            path: string;

            top_status: number;
          }
        }

        export interface Target {
          hosts: Array<string>;

          kind: 'worker' | 'origin';

          /**
           * UTC ISO-8601 interval. Start is inclusive, end is exclusive, and the interval
           * must be positive and at most seven days.
           */
          telemetry_window?: Target.TelemetryWindow;
        }

        export namespace Target {
          /**
           * UTC ISO-8601 interval. Start is inclusive, end is exclusive, and the interval
           * must be positive and at most seven days.
           */
          export interface TelemetryWindow {
            end: string;

            start: string;
          }
        }

        export interface WAF {
          hit_volume: number;

          rules: Array<WAF.Rule>;
        }

        export namespace WAF {
          export interface Rule {
            id: string;

            hit_volume: number;

            paths: Array<Rule.Path>;

            rule_id: string;

            rule_version: number | null;
          }

          export namespace Rule {
            export interface Path {
              id: string;

              hit_volume: number;

              host: string;

              path: string;
            }
          }
        }

        export interface WebAssets {
          operations: Array<WebAssets.Operation>;

          paths: Array<WebAssets.Path>;

          risk_types: Array<WebAssets.RiskType>;
        }

        export namespace WebAssets {
          export interface Operation {
            id: string;

            endpoint: string;

            host: string;

            method: string;

            risk_labels: Array<Operation.RiskLabel>;

            performance?: Operation.Performance;
          }

          export namespace Operation {
            export interface RiskLabel {
              description: string | null;

              name: string;
            }

            export interface Performance {
              avg_origin_latency_ms: number | null;

              error_rate: number;

              estimated_requests: number;
            }
          }

          export interface Path {
            id: string;

            avg_origin_latency_ms: number | null;

            error_rate: number;

            estimated_requests: number;

            host: string;

            path: string;
          }

          export interface RiskType {
            description: string | null;

            name: string;

            operation_count: number;
          }
        }
      }

      export interface ExternalLink {
        title: string;

        url: string;
      }
    }
  }

  export interface Repository {
    id: string;

    name: string;

    report_status: 'not_ready' | 'pending_review' | 'published' | 'withdrawn';

    scan_status: 'requested' | 'accepted' | 'running' | 'completed' | 'failed' | 'rejected' | 'cancelled';
  }
}

export interface ScanCreateParams {
  /**
   * Path param
   */
  account_id: string;

  /**
   * Body param
   */
  repos: Array<string>;

  /**
   * Body param: Explicit hostname scopes. Every hostname must be authorized for its
   * repository before review admission; rejected scopes return 422 and do not
   * persist a scan request.
   */
  repo_hosts?: { [key: string]: Array<string> };

  /**
   * Body param: UTC ISO-8601 interval. Start is inclusive, end is exclusive, and the
   * interval must be positive and at most seven days.
   */
  telemetry_window?: ScanCreateParams.TelemetryWindow;

  /**
   * Header param: Optional. Supply this header to safely retry a request. Required
   * when `worker_script_name` is supplied.
   */
  'Idempotency-Key'?: string;
}

export namespace ScanCreateParams {
  /**
   * UTC ISO-8601 interval. Start is inclusive, end is exclusive, and the interval
   * must be positive and at most seven days.
   */
  export interface TelemetryWindow {
    end: string;

    start: string;
  }
}

export interface ScanListParams extends CursorLimitPaginationParams {
  /**
   * Path param
   */
  account_id: string;

  /**
   * Query param
   */
  repo?: string;

  /**
   * Query param: Repeat parameter or provide comma-separated values.
   */
  status?:
    | 'requested'
    | 'accepted'
    | 'running'
    | 'completed'
    | 'failed'
    | 'rejected'
    | 'cancelled'
    | Array<'requested' | 'accepted' | 'running' | 'completed' | 'failed' | 'rejected' | 'cancelled'>;
}

export interface ScanGetParams {
  account_id: string;
}

export interface ScanGetReportParams {
  account_id: string;
}

export declare namespace Scans {
  export {
    type ScanCreateResponse as ScanCreateResponse,
    type ScanListResponse as ScanListResponse,
    type ScanGetResponse as ScanGetResponse,
    type ScanGetReportResponse as ScanGetReportResponse,
    type ScanListResponsesCursorLimitPagination as ScanListResponsesCursorLimitPagination,
    type ScanCreateParams as ScanCreateParams,
    type ScanListParams as ScanListParams,
    type ScanGetParams as ScanGetParams,
    type ScanGetReportParams as ScanGetReportParams,
  };
}
