import { mkdir, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import type {
  AppConfig,
  AuthSessionSummary,
  CreditSummary,
  DiagnosticsExportResult,
  GatewayHealth,
  GatewayStatus,
  LogEntry,
  ModelConfigSummary,
  RuntimeCloudStatus,
  RuntimeStatus,
  RuntimeTelemetryStatus,
  SkillSummary,
  SystemSummary,
  UserProfileSummary,
  WorkspaceSummary
} from "@qjclaw/shared-types";
import { getRuntimeCloudApiTarget } from "./app-config.js";
import type { LocalOpenClawGatewayConfig } from "./openclaw-local-config.js";
import type { ProjectBundleSyncStatus } from "./project-bundle.js";
import type { StartupLogger } from "./startup-logger.js";

interface DiagnosticsSnapshotInput {
  config: AppConfig;
  gatewayStatus: GatewayStatus;
  gatewayHealth: GatewayHealth;
  logs: LogEntry[];
  appVersion: string;
  localOpenClawConfig?: LocalOpenClawGatewayConfig | null;
  secretBackend: string;
  authSession?: AuthSessionSummary;
  profile?: UserProfileSummary | null;
  credits?: CreditSummary | null;
  skills?: SkillSummary[];
  modelConfig?: ModelConfigSummary | null;
  cloudApiError?: string;
  systemSummary: SystemSummary;
  runtimeStatus?: RuntimeStatus;
  runtimeLogs?: LogEntry[];
  runtimeCloudStatus?: RuntimeCloudStatus;
  runtimeTelemetryStatus?: RuntimeTelemetryStatus;
  workspaceSummary?: WorkspaceSummary;
  bundleSyncStatus?: ProjectBundleSyncStatus;
  startupLogPath?: string;
  reason?: string;
}

function toSafeStamp(value: string): string {
  return value.replace(/[:.]/g, "-");
}

export class DiagnosticsService {
  private readonly userDataPath: string;
  private readonly startupLogger?: StartupLogger;

  constructor(userDataPath: string, startupLogger?: StartupLogger) {
    this.userDataPath = userDataPath;
    this.startupLogger = startupLogger;
  }

  async exportSnapshot(input: DiagnosticsSnapshotInput): Promise<DiagnosticsExportResult> {
    const createdAt = new Date().toISOString();
    const diagnosticsDir = path.join(this.userDataPath, "diagnostics");
    const filePath = path.join(diagnosticsDir, `snapshot-${toSafeStamp(createdAt)}.json`);
    const runtimeCloudTarget = getRuntimeCloudApiTarget(input.config);

    const payload = {
      createdAt,
      reason: input.reason,
      startupLogPath: input.startupLogPath,
      app: {
        name: input.systemSummary.appName,
        version: input.appVersion,
        platform: process.platform,
        arch: process.arch,
        nodeVersion: process.version,
        electronVersion: process.versions.electron ?? "unknown",
        hostname: os.hostname(),
        isPackaged: input.systemSummary.isPackaged
      },
      paths: {
        appPath: input.systemSummary.appPath,
        resourcesPath: input.systemSummary.resourcesPath,
        userData: input.systemSummary.userDataPath,
        logs: input.systemSummary.logsPath,
        cwd: process.cwd(),
        homedir: os.homedir()
      },
      configSummary: {
        provider: input.config.provider,
        baseUrl: input.config.baseUrl,
        defaultModel: input.config.defaultModel,
        expertModelConfig: input.config.expertModelConfig,
        workspacePath: input.config.workspacePath,
        gatewayUrl: input.config.gatewayUrl,
        cloudApiBaseUrl: input.config.cloudApiBaseUrl,
        runtimeCloudApiBaseUrl: input.config.runtimeCloudApiBaseUrl,
        runtimeCloudApiResolvedBaseUrl: runtimeCloudTarget.baseUrl,
        runtimeCloudApiBaseUrlSource: runtimeCloudTarget.source,
        runtimeMode: input.config.runtimeMode,
        apiKeyConfigured: input.config.apiKeyConfigured,
        gatewayTokenConfigured: input.config.gatewayTokenConfigured,
        authTokenConfigured: input.config.authTokenConfigured,
        secretBackend: input.secretBackend
      },
      cloud: {
        authSession: input.authSession,
        profile: input.profile,
        credits: input.credits,
        skillCount: input.skills?.length ?? 0,
        skills: input.skills ?? [],
        modelConfig: input.modelConfig,
        cloudApiError: input.cloudApiError
      },
      runtimeCloud: input.runtimeCloudStatus
        ? {
            state: input.runtimeCloudStatus.state,
            baseUrl: input.runtimeCloudStatus.baseUrl,
            baseUrlSource: input.runtimeCloudStatus.baseUrlSource,
            baseHost: input.runtimeCloudStatus.baseHost,
            apiKeyConfigured: input.runtimeCloudStatus.apiKeyConfigured,
            lastFetchedAt: input.runtimeCloudStatus.lastFetchedAt,
            lastError: input.runtimeCloudStatus.lastError,
            config: input.runtimeCloudStatus.config
          }
        : null,
      workspace: input.workspaceSummary ?? null,
      bundleSync: input.bundleSyncStatus
        ? { ...input.bundleSyncStatus }
        : null,
      runtimeTelemetry: input.runtimeTelemetryStatus ?? null,
      runtime: {
        status: input.runtimeStatus,
        recentLogs: input.runtimeLogs ?? []
      },
      gateway: {
        status: input.gatewayStatus,
        health: input.gatewayHealth,
        recentLogs: input.logs
      },
      localOpenClaw: input.localOpenClawConfig
        ? {
            detected: true,
            sourcePath: input.localOpenClawConfig.sourcePath,
            gatewayUrl: input.localOpenClawConfig.gatewayUrl,
            gatewayTokenConfigured: Boolean(input.localOpenClawConfig.gatewayToken)
          }
        : {
            detected: false
          }
    };

    await mkdir(diagnosticsDir, { recursive: true });
    await writeFile(filePath, JSON.stringify(payload, null, 2), "utf8");
    await this.startupLogger?.info("diagnostics", "snapshot.exported", "Diagnostics snapshot exported.", {
      diagnosticsPath: filePath,
      startupLogPath: input.startupLogPath,
      reason: input.reason,
      workspacePhase: input.workspaceSummary?.startupPhase,
      workspaceLaunchState: input.workspaceSummary?.chatLaunchState
    });

    return {
      filePath,
      createdAt,
      startupLogPath: input.startupLogPath
    };
  }
}
