import { makeApi, Zodios, type ZodiosOptions } from "@zodios/core";
import { z } from "zod";

export type AnalysisModuleConfig = {
  analysis_prompt: string;
  context_selector: ContextSelectorConfig;
  dependencies: Array<string>;
  id?: (string | null) | undefined;
  llm_config?: (null | LlmConfig) | undefined;
  name: string;
  output_type: string;
};
export type ContextSelectorConfig = SelectionMode;
export type SelectionMode =
  | {
      Manual: {
        rules: Array<string>;
      };
    }
  | {
      Auto: Partial<{
        llm_config: null | LlmConfig;
      }>;
    }
  | {
      Hybrid: {
        llm_config?: (null | LlmConfig) | undefined;
        selection_prompt: string;
      };
    };
export type LlmConfig = Partial<{
  max_tokens: number | null;
  model_id: string | null;
  temperature: number | null;
}>;
export type AnalysisTemplateSet = {
  modules: {};
  name: string;
};
export type AnalysisTemplateSets = {};
export type ConfigFieldSchema = {
  default_value?: (string | null) | undefined;
  description?: (string | null) | undefined;
  field_type: FieldType;
  key: ConfigKey;
  label: string;
  options?: (Array<string> | null) | undefined;
  placeholder?: (string | null) | undefined;
  required: boolean;
};
export type FieldType = "Text" | "Password" | "Url" | "Boolean" | "Select";
export type ConfigKey =
  | "ApiKey"
  | "ApiToken"
  | "ApiUrl"
  | "BaseUrl"
  | "SecretKey"
  | "Username"
  | "Password"
  | "SandboxMode"
  | "Region";
export type DataSourceConfig = {
  api_key?: (string | null) | undefined;
  api_url?: (string | null) | undefined;
  enabled: boolean;
  provider: DataSourceProvider;
};
export type DataSourceProvider = "Tushare" | "Finnhub" | "Alphavantage" | "Yfinance";
export type DataSourcesConfig = {};
export type HealthStatus = {
  details: {};
  module_id: string;
  status: ServiceStatus;
  version: string;
};
export type ServiceStatus = "Ok" | "Degraded" | "Unhealthy";
export type LlmProvider = {
  api_base_url: string;
  api_key: string;
  models: Array<LlmModel>;
  name: string;
};
export type LlmModel = {
  is_active: boolean;
  model_id: string;
  name?: (string | null) | undefined;
};
export type LlmProvidersConfig = {};
export type ProviderMetadata = {
  config_schema: Array<ConfigFieldSchema>;
  description: string;
  icon_url?: (string | null) | undefined;
  id: string;
  name_cn: string;
  name_en: string;
  supports_test_connection: boolean;
};
export type StartWorkflowCommand = {
  market: string;
  request_id: string;
  symbol: CanonicalSymbol;
  template_id: string;
};
export type CanonicalSymbol = string;
export type TaskNode = {
  display_name?: (string | null) | undefined;
  id: string;
  initial_status: TaskStatus;
  name: string;
  type: TaskType;
};
export type TaskStatus =
  | "Pending"
  | "Scheduled"
  | "Running"
  | "Completed"
  | "Failed"
  | "Skipped";
export type TaskType = "DataFetch" | "DataProcessing" | "Analysis";
export type TaskProgress = {
  details: string;
  progress_percent: number;
  request_id: string;
  started_at: string;
  status: ObservabilityTaskStatus;
  task_name: string;
};
export type ObservabilityTaskStatus = "Queued" | "InProgress" | "Completed" | "Failed";
export type WorkflowDag = {
  edges: Array<TaskDependency>;
  nodes: Array<TaskNode>;
};
export type TaskDependency = {
  from: string;
  to: string;
};
export type WorkflowEvent =
  | {
      payload: {
        task_graph: WorkflowDag;
        timestamp: number;
      };
      type: "WorkflowStarted";
    }
  | {
      payload: {
        input_commit?: (string | null) | undefined;
        message?: (string | null) | undefined;
        output_commit?: (string | null) | undefined;
        progress?: (number | null) | undefined;
        status: TaskStatus;
        task_id: string;
        task_type: TaskType;
        timestamp: number;
      };
      type: "TaskStateChanged";
    }
  | {
      payload: {
        content_delta: string;
        index: number;
        task_id: string;
      };
      type: "TaskStreamUpdate";
    }
  | {
      payload: {
        level: string;
        message: string;
        task_id: string;
        timestamp: number;
      };
      type: "TaskLog";
    }
  | {
      payload: {
        end_timestamp: number;
        result_summary?: unknown | undefined;
      };
      type: "WorkflowCompleted";
    }
  | {
      payload: {
        end_timestamp: number;
        is_fatal: boolean;
        reason: string;
      };
      type: "WorkflowFailed";
    }
  | {
      payload: {
        task_graph: WorkflowDag;
        tasks_metadata: {};
        tasks_output: {};
        tasks_status: {};
        timestamp: number;
      };
      type: "WorkflowStateSnapshot";
    };
export type TaskMetadata = Partial<{
  execution_log_path: string | null;
  output_path: string | null;
}>;
export type WorkflowHistoryDto = {
  created_at: string;
  end_time?: (string | null) | undefined;
  market: string;
  request_id: string;
  snapshot_data: Value;
  start_time: string;
  status: string;
  symbol: string;
  template_id?: (string | null) | undefined;
};
export type Value = unknown;

export const DataSourceProvider = z.enum([
  "Tushare",
  "Finnhub",
  "Alphavantage",
  "Yfinance",
]);
export const DataSourceConfig = z.object({
  api_key: z.union([z.string(), z.null()]).optional(),
  api_url: z.union([z.string(), z.null()]).optional(),
  enabled: z.boolean(),
  provider: DataSourceProvider,
});
export const DataSourcesConfig =
  z.record(DataSourceConfig);
export const TestLlmConfigRequest = z.object({
  api_base_url: z.string(),
  api_key: z.string(),
  model_id: z.string(),
});
export const LlmModel = z.object({
  is_active: z.boolean(),
  model_id: z.string(),
  name: z.union([z.string(), z.null()]).optional(),
});
export const LlmProvider = z.object({
  api_base_url: z.string(),
  api_key: z.string(),
  models: z.array(LlmModel),
  name: z.string(),
});
export const LlmProvidersConfig = z.record(LlmProvider);
export const AnalysisTemplateSummary = z.object({ id: z.string(), name: z.string() });
export const LlmConfig = z
  .object({
    max_tokens: z.union([z.number(), z.null()]),
    model_id: z.union([z.string(), z.null()]),
    temperature: z.union([z.number(), z.null()]),
  })
  .partial();
export const SelectionMode = z.union([
  z
    .object({ Manual: z.object({ rules: z.array(z.string()) }).passthrough() })
    .passthrough(),
  z
    .object({
      Auto: z
        .object({ llm_config: z.union([z.null(), LlmConfig]) })
        .partial()
        .passthrough(),
    })
    .passthrough(),
  z
    .object({
      Hybrid: z
        .object({
          llm_config: z.union([z.null(), LlmConfig]).optional(),
          selection_prompt: z.string(),
        })
        .passthrough(),
    })
    .passthrough(),
]);
export const ContextSelectorConfig = SelectionMode;
export const AnalysisModuleConfig = z.object({
  analysis_prompt: z.string(),
  context_selector: ContextSelectorConfig,
  dependencies: z.array(z.string()),
  id: z.union([z.string(), z.null()]).optional(),
  llm_config: z.union([z.null(), LlmConfig]).optional(),
  name: z.string(),
  output_type: z.string(),
});
export const AnalysisTemplateSet = z.object({
  modules: z.record(AnalysisModuleConfig),
  name: z.string(),
});
export const TestConfigRequest = z.object({ data: z.unknown(), type: z.string() });
export const TestConnectionResponse = z.object({
  message: z.string(),
  success: z.boolean(),
});
export const DiscoverPreviewRequest = z.object({
  api_base_url: z.string(),
  api_key: z.string(),
});
export const WorkflowHistorySummaryDto = z.object({
  end_time: z.union([z.string(), z.null()]).optional(),
  market: z.string(),
  request_id: z.string().uuid(),
  start_time: z.string().datetime({ offset: true }),
  status: z.string(),
  symbol: z.string(),
  template_id: z.union([z.string(), z.null()]).optional(),
});
export const Value = z.unknown();
export const WorkflowHistoryDto = z.object({
  created_at: z.string().datetime({ offset: true }),
  end_time: z.union([z.string(), z.null()]).optional(),
  market: z.string(),
  request_id: z.string().uuid(),
  snapshot_data: Value,
  start_time: z.string().datetime({ offset: true }),
  status: z.string(),
  symbol: z.string(),
  template_id: z.union([z.string(), z.null()]).optional(),
});
export const FieldType = z.enum(["Text", "Password", "Url", "Boolean", "Select"]);
export const ConfigKey = z.enum([
  "ApiKey",
  "ApiToken",
  "ApiUrl",
  "BaseUrl",
  "SecretKey",
  "Username",
  "Password",
  "SandboxMode",
  "Region",
]);
export const ConfigFieldSchema = z.object({
  default_value: z.union([z.string(), z.null()]).optional(),
  description: z.union([z.string(), z.null()]).optional(),
  field_type: FieldType,
  key: ConfigKey,
  label: z.string(),
  options: z.union([z.array(z.string()), z.null()]).optional(),
  placeholder: z.union([z.string(), z.null()]).optional(),
  required: z.boolean(),
});
export const ProviderMetadata = z.object({
  config_schema: z.array(ConfigFieldSchema),
  description: z.string(),
  icon_url: z.union([z.string(), z.null()]).optional(),
  id: z.string(),
  name_cn: z.string(),
  name_en: z.string(),
  supports_test_connection: z.boolean(),
});
export const SymbolResolveRequest = z.object({
  market: z.union([z.string(), z.null()]).optional(),
  symbol: z.string(),
});
export const SymbolResolveResponse = z.object({
  market: z.string(),
  symbol: z.string(),
});
export const DataRequest = z.object({
  market: z.union([z.string(), z.null()]).optional(),
  symbol: z.string(),
  template_id: z.string(),
});
export const RequestAcceptedResponse = z.object({
  market: z.string(),
  request_id: z.string().uuid(),
  symbol: z.string(),
});
export const ObservabilityTaskStatus = z.enum([
  "Queued",
  "InProgress",
  "Completed",
  "Failed",
]);
export const TaskProgress = z.object({
  details: z.string(),
  progress_percent: z.number().int().gte(0),
  request_id: z.string().uuid(),
  started_at: z.string().datetime({ offset: true }),
  status: ObservabilityTaskStatus,
  task_name: z.string(),
});
export const AnalysisTemplateSets =
  z.record(AnalysisTemplateSet);
export const CanonicalSymbol = z.string();
export const ServiceStatus = z.enum(["Ok", "Degraded", "Unhealthy"]);
export const HealthStatus = z.object({
  details: z.record(z.string()),
  module_id: z.string(),
  status: ServiceStatus,
  version: z.string(),
});
export const StartWorkflowCommand = z.object({
  market: z.string(),
  request_id: z.string().uuid(),
  symbol: CanonicalSymbol,
  template_id: z.string(),
});
export const TaskDependency = z.object({
  from: z.string(),
  to: z.string(),
});
export const TaskMetadata = z
  .object({
    execution_log_path: z.union([z.string(), z.null()]),
    output_path: z.union([z.string(), z.null()]),
  })
  .partial();
export const TaskStatus = z.enum([
  "Pending",
  "Scheduled",
  "Running",
  "Completed",
  "Failed",
  "Skipped",
]);
export const TaskType = z.enum(["DataFetch", "DataProcessing", "Analysis"]);
export const TaskNode = z.object({
  display_name: z.union([z.string(), z.null()]).optional(),
  id: z.string(),
  initial_status: TaskStatus,
  name: z.string(),
  type: TaskType,
});
export const WorkflowDag = z.object({
  edges: z.array(TaskDependency),
  nodes: z.array(TaskNode),
});
export const WorkflowEvent = z.union([
  z
    .object({
      payload: z
        .object({ task_graph: WorkflowDag, timestamp: z.number().int() })
        .passthrough(),
      type: z.literal("WorkflowStarted"),
    })
    .passthrough(),
  z
    .object({
      payload: z
        .object({
          input_commit: z.union([z.string(), z.null()]).optional(),
          message: z.union([z.string(), z.null()]).optional(),
          output_commit: z.union([z.string(), z.null()]).optional(),
          progress: z.union([z.number(), z.null()]).optional(),
          status: TaskStatus,
          task_id: z.string(),
          task_type: TaskType,
          timestamp: z.number().int(),
        })
        .passthrough(),
      type: z.literal("TaskStateChanged"),
    })
    .passthrough(),
  z
    .object({
      payload: z
        .object({
          content_delta: z.string(),
          index: z.number().int().gte(0),
          task_id: z.string(),
        })
        .passthrough(),
      type: z.literal("TaskStreamUpdate"),
    })
    .passthrough(),
  z
    .object({
      payload: z
        .object({
          level: z.string(),
          message: z.string(),
          task_id: z.string(),
          timestamp: z.number().int(),
        })
        .passthrough(),
      type: z.literal("TaskLog"),
    })
    .passthrough(),
  z
    .object({
      payload: z
        .object({
          end_timestamp: z.number().int(),
          result_summary: z.unknown().optional(),
        })
        .passthrough(),
      type: z.literal("WorkflowCompleted"),
    })
    .passthrough(),
  z
    .object({
      payload: z
        .object({
          end_timestamp: z.number().int(),
          is_fatal: z.boolean(),
          reason: z.string(),
        })
        .passthrough(),
      type: z.literal("WorkflowFailed"),
    })
    .passthrough(),
  z
    .object({
      payload: z
        .object({
          logs: z.array(z.string()),
          task_graph: WorkflowDag,
          tasks_metadata: z.record(TaskMetadata),
          tasks_output: z.record(z.union([z.string(), z.null()])),
          tasks_status: z.record(TaskStatus),
          timestamp: z.number().int(),
        })
        .passthrough(),
      type: z.literal("WorkflowStateSnapshot"),
    })
    .passthrough(),
]);

export const schemas = {
  DataSourceProvider,
  DataSourceConfig,
  DataSourcesConfig,
  TestLlmConfigRequest,
  LlmModel,
  LlmProvider,
  LlmProvidersConfig,
  AnalysisTemplateSummary,
  LlmConfig,
  SelectionMode,
  ContextSelectorConfig,
  AnalysisModuleConfig,
  AnalysisTemplateSet,
  TestConfigRequest,
  TestConnectionResponse,
  DiscoverPreviewRequest,
  WorkflowHistorySummaryDto,
  Value,
  WorkflowHistoryDto,
  FieldType,
  ConfigKey,
  ConfigFieldSchema,
  ProviderMetadata,
  SymbolResolveRequest,
  SymbolResolveResponse,
  DataRequest,
  RequestAcceptedResponse,
  ObservabilityTaskStatus,
  TaskProgress,
  AnalysisTemplateSets,
  CanonicalSymbol,
  ServiceStatus,
  HealthStatus,
  StartWorkflowCommand,
  TaskDependency,
  TaskMetadata,
  TaskStatus,
  TaskType,
  TaskNode,
  WorkflowDag,
  WorkflowEvent,
};

export const endpoints = makeApi([
  {
    method: "get",
    path: "/api/v1/configs/data_sources",
    alias: "get_data_sources_config",
    requestFormat: "json",
    response: z.record(DataSourceConfig),
  },
  {
    method: "put",
    path: "/api/v1/configs/data_sources",
    alias: "update_data_sources_config",
    requestFormat: "json",
    parameters: [
      {
        name: "body",
        type: "Body",
        schema: z.record(DataSourceConfig),
      },
    ],
    response: z.record(DataSourceConfig),
  },
  {
    method: "get",
    path: "/api/v1/configs/llm_providers",
    alias: "get_llm_providers_config",
    requestFormat: "json",
    response: z.record(LlmProvider),
  },
  {
    method: "put",
    path: "/api/v1/configs/llm_providers",
    alias: "update_llm_providers_config",
    requestFormat: "json",
    parameters: [
      {
        name: "body",
        type: "Body",
        schema: z.record(LlmProvider),
      },
    ],
    response: z.record(LlmProvider),
  },
  {
    method: "post",
    path: "/api/v1/configs/llm/test",
    alias: "test_llm_config",
    requestFormat: "json",
    parameters: [
      {
        name: "body",
        type: "Body",
        schema: TestLlmConfigRequest,
      },
    ],
    response: z.void(),
  },
  {
    method: "get",
    path: "/api/v1/configs/templates",
    alias: "get_templates",
    requestFormat: "json",
    response: z.array(AnalysisTemplateSummary),
  },
  {
    method: "get",
    path: "/api/v1/configs/templates/:id",
    alias: "get_template_by_id",
    requestFormat: "json",
    parameters: [
      {
        name: "id",
        type: "Path",
        schema: z.string(),
      },
    ],
    response: AnalysisTemplateSet,
    errors: [
      {
        status: 404,
        description: `Template not found`,
        schema: z.void(),
      },
    ],
  },
  {
    method: "put",
    path: "/api/v1/configs/templates/:id",
    alias: "update_template",
    requestFormat: "json",
    parameters: [
      {
        name: "body",
        type: "Body",
        schema: AnalysisTemplateSet,
      },
      {
        name: "id",
        type: "Path",
        schema: z.string(),
      },
    ],
    response: AnalysisTemplateSet,
    errors: [
      {
        status: 404,
        description: `Template not found`,
        schema: z.void(),
      },
    ],
  },
  {
    method: "delete",
    path: "/api/v1/configs/templates/:id",
    alias: "delete_template",
    requestFormat: "json",
    parameters: [
      {
        name: "id",
        type: "Path",
        schema: z.string(),
      },
    ],
    response: z.void(),
    errors: [
      {
        status: 404,
        description: `Template not found`,
        schema: z.void(),
      },
    ],
  },
  {
    method: "post",
    path: "/api/v1/configs/test",
    alias: "test_data_source_config",
    requestFormat: "json",
    parameters: [
      {
        name: "body",
        type: "Body",
        schema: z.object({ data: z.unknown(), type: z.string() }),
      },
    ],
    response: TestConnectionResponse,
  },
  {
    method: "post",
    path: "/api/v1/discover-models",
    alias: "discover_models_preview",
    requestFormat: "json",
    parameters: [
      {
        name: "body",
        type: "Body",
        schema: DiscoverPreviewRequest,
      },
    ],
    response: z.void(),
    errors: [
      {
        status: 502,
        description: `Provider error`,
        schema: z.void(),
      },
    ],
  },
  {
    method: "get",
    path: "/api/v1/discover-models/:provider_id",
    alias: "discover_models",
    requestFormat: "json",
    parameters: [
      {
        name: "provider_id",
        type: "Path",
        schema: z.string(),
      },
    ],
    response: z.void(),
    errors: [
      {
        status: 404,
        description: `Provider not found`,
        schema: z.void(),
      },
      {
        status: 502,
        description: `Provider error`,
        schema: z.void(),
      },
    ],
  },
  {
    method: "get",
    path: "/api/v1/history",
    alias: "get_workflow_histories",
    requestFormat: "json",
    parameters: [
      {
        name: "symbol",
        type: "Query",
        schema: z.string().optional(),
      },
      {
        name: "limit",
        type: "Query",
        schema: z.number().int().optional(),
      },
    ],
    response: z.array(WorkflowHistorySummaryDto),
  },
  {
    method: "get",
    path: "/api/v1/history/:request_id",
    alias: "get_workflow_history_by_id",
    requestFormat: "json",
    parameters: [
      {
        name: "request_id",
        type: "Path",
        schema: z.string().uuid(),
      },
    ],
    response: WorkflowHistoryDto,
    errors: [
      {
        status: 404,
        description: `History not found`,
        schema: z.void(),
      },
    ],
  },
  {
    method: "get",
    path: "/api/v1/registry/providers",
    alias: "get_registered_providers",
    requestFormat: "json",
    response: z.array(ProviderMetadata),
  },
  {
    method: "post",
    path: "/api/v1/tools/resolve-symbol",
    alias: "resolve_symbol",
    requestFormat: "json",
    parameters: [
      {
        name: "body",
        type: "Body",
        schema: SymbolResolveRequest,
      },
    ],
    response: SymbolResolveResponse,
  },
  {
    method: "post",
    path: "/api/v1/workflow/start",
    alias: "start_workflow",
    requestFormat: "json",
    parameters: [
      {
        name: "body",
        type: "Body",
        schema: DataRequest,
      },
    ],
    response: RequestAcceptedResponse,
  },
  {
    method: "get",
    path: "/health",
    alias: "health_check",
    requestFormat: "json",
    response: z.void(),
  },
  {
    method: "get",
    path: "/tasks/:request_id",
    alias: "get_task_progress",
    requestFormat: "json",
    parameters: [
      {
        name: "request_id",
        type: "Path",
        schema: z.string().uuid(),
      },
    ],
    response: z.array(TaskProgress),
    errors: [
      {
        status: 404,
        description: `Tasks not found`,
        schema: z.void(),
      },
    ],
  },
]);

export const api = new Zodios(endpoints);

export function createApiClient(baseUrl: string, options?: ZodiosOptions) {
  return new Zodios(baseUrl, endpoints, options);
}
