import fs from 'node:fs';
import path from 'node:path';
import {
  readMatrixCliConfig,
  resetMatrixCliConfig,
  resolvePackageRegistry,
  setMatrixCliConfigValue,
  type IMatrixCliConfig,
} from '../utils/config-store.js';

export interface IConfigCommandOptions {
  readonly cwd?: string;
  readonly configPath?: string;
}

export interface IConfigGetResult {
  readonly key: string;
  readonly value: string | undefined;
  readonly source?: 'explicit' | 'env' | 'config' | 'default';
  readonly configPath: string;
}

export interface IConfigListResult {
  readonly configPath: string;
  readonly values: IMatrixCliConfig;
  readonly effective: {
    readonly registry: string;
    readonly registrySource: 'explicit' | 'env' | 'config' | 'default';
  };
}

export interface IConfigSetResult {
  readonly key: string;
  readonly value: string;
  readonly configPath: string;
}

export interface IConfigResetResult {
  readonly configPath: string;
  readonly values: IMatrixCliConfig;
}

export type ConfigClassificationKind =
  | 'direct-actor-input'
  | 'package-declaration'
  | 'runtime-host-desired-state'
  | 'credential-link-state'
  | 'runtime-host-generated-state'
  | 'runtime-host-preset'
  | 'platform-deployment'
  | 'deletion-candidate'
  | 'unknown';

export interface IConfigExplainResult {
  readonly path: string;
  readonly relativePath: string;
  readonly exists: boolean;
  readonly kind: ConfigClassificationKind;
  readonly owner: string;
  readonly authoredBy: string;
  readonly directRunReads: boolean;
  readonly managedHostReads: boolean;
  readonly generated: boolean;
  readonly recommendedAction: string;
  readonly notes: readonly string[];
}

function assertSupportedKey(key: string): 'registry' {
  const normalized = key.trim();
  if (normalized !== 'registry') {
    throw new Error(`MX_CONFIG_INVALID: unsupported config key "${key}"`);
  }
  return normalized;
}

export async function configGetCommand(
  key: string,
  options: IConfigCommandOptions = {},
): Promise<IConfigGetResult> {
  const normalizedKey = assertSupportedKey(key);
  const stored = readMatrixCliConfig(options);
  const effective = resolvePackageRegistry(undefined, options);
  return {
    key: normalizedKey,
    value: stored.values.registry ?? effective.registry,
    source: stored.values.registry ? 'config' : effective.source,
    configPath: stored.configPath,
  };
}

export async function configListCommand(options: IConfigCommandOptions = {}): Promise<IConfigListResult> {
  const stored = readMatrixCliConfig(options);
  const effective = resolvePackageRegistry(undefined, options);
  return {
    configPath: stored.configPath,
    values: stored.values,
    effective: {
      registry: effective.registry,
      registrySource: effective.source,
    },
  };
}

export async function configSetCommand(
  key: string,
  value: string,
  options: IConfigCommandOptions = {},
): Promise<IConfigSetResult> {
  const normalizedKey = assertSupportedKey(key);
  const result = setMatrixCliConfigValue(normalizedKey, value, options);
  return {
    key: normalizedKey,
    value: result.values.registry ?? '',
    configPath: result.configPath,
  };
}

export async function configResetCommand(options: IConfigCommandOptions = {}): Promise<IConfigResetResult> {
  return resetMatrixCliConfig(options);
}

export async function configExplainCommand(
  targetPath: string,
  options: IConfigCommandOptions = {},
): Promise<IConfigExplainResult> {
  const cwd = options.cwd ?? process.cwd();
  const absolutePath = path.resolve(cwd, targetPath);
  const relativePath = normalizePath(path.relative(cwd, absolutePath) || path.basename(absolutePath));
  const exists = fs.existsSync(absolutePath);
  return {
    path: absolutePath,
    relativePath,
    exists,
    ...classifyConfigPath(relativePath),
  };
}

function classifyConfigPath(relativePath: string): Omit<IConfigExplainResult, 'path' | 'relativePath' | 'exists'> {
  const normalized = normalizePath(relativePath);
  const basename = path.posix.basename(normalized);
  const segments = normalized.split('/').filter(Boolean);

  if (basename === 'ActorRunnerSmokeActor.mjs' || basename.endsWith('Actor.ts') || basename.endsWith('Actor.mjs')) {
    return classification({
      kind: 'direct-actor-input',
      owner: 'Standalone Actor Runner',
      authoredBy: 'CLI caller or package author',
      directRunReads: true,
      managedHostReads: false,
      generated: false,
      recommendedAction: 'keep as direct actor input; do not register Host-managed state',
      notes: ['Direct actor execution receives this path from the CLI caller.'],
    });
  }

  if (basename === 'matrix.json') {
    return classification({
      kind: 'package-declaration',
      owner: 'Package',
      authoredBy: 'package author or scaffold',
      directRunReads: true,
      managedHostReads: true,
      generated: false,
      recommendedAction: 'keep; package declarations are shared by direct and managed execution',
      notes: [`${basename} is package-authored declaration state.`],
    });
  }

  if (basename === 'package.json.matrix') {
    return classification({
      kind: 'package-declaration',
      owner: 'Package',
      authoredBy: 'package author or scaffold',
      directRunReads: true,
      managedHostReads: true,
      generated: false,
      recommendedAction: 'migrate to matrix.json when a package-local matrix.json exists',
      notes: ['This is a duplicate package manifest candidate, not Runtime Host state.'],
    });
  }

  if (basename === 'host.json' || basename === 'workspace.json' || basename === 'daemon.json') {
    return classification({
      kind: 'runtime-host-desired-state',
      owner: 'Runtime Host',
      authoredBy: 'developer, operator, or Host setup tool',
      directRunReads: false,
      managedHostReads: true,
      generated: false,
      recommendedAction: 'normalize behind the Runtime Host Plan before changing shape',
      notes: ['Direct actor/package execution must not read this file.'],
    });
  }

  if (basename.endsWith('.environment.json') && segments.includes('.matrix')) {
    return classification({
      kind: 'runtime-host-desired-state',
      owner: 'Runtime Host',
      authoredBy: 'developer, operator, or package environment author',
      directRunReads: false,
      managedHostReads: true,
      generated: false,
      recommendedAction: 'normalize into Runtime Host desired-state model',
      notes: ['Package environment manifests belong to managed execution, not direct cloud-bus run.'],
    });
  }

  if (segments.includes('credentials') || basename === 'matrix-api-key.json' || basename === 'hivecast-link.json') {
    return classification({
      kind: 'credential-link-state',
      owner: 'Credentials layer',
      authoredBy: 'CLI, cloud exchange, or operator',
      directRunReads: true,
      managedHostReads: true,
      generated: false,
      recommendedAction: 'keep secret; never commit; use only through configured credential resolvers',
      notes: ['Direct-run may read stored API keys; Runtime Host may read Host/link credentials.'],
    });
  }

  if (
    basename === 'host.status.json'
    || basename === 'metadata.webapp'
    || segments.includes('runtimes')
    || segments.includes('runtime-env')
    || segments.includes('package-records')
  ) {
    return classification({
      kind: 'runtime-host-generated-state',
      owner: 'Runtime Host reconciler',
      authoredBy: 'generated by Host runtime',
      directRunReads: false,
      managedHostReads: true,
      generated: true,
      recommendedAction: 'keep out of authored config; safe to regenerate from managed Host state',
      notes: ['Direct actor/package execution must not create this state.'],
    });
  }

  if (
    normalized.includes('/deployments/nodes/')
    || normalized.startsWith('deployments/nodes/')
    || normalized.includes('/dist/profiles/')
    || normalized.startsWith('dist/profiles/')
    || basename.endsWith('.profile.json')
    || basename.endsWith('.node.json')
  ) {
    return classification({
      kind: 'runtime-host-preset',
      owner: 'Distribution profile resolver',
      authoredBy: 'release engineer',
      directRunReads: false,
      managedHostReads: true,
      generated: false,
      recommendedAction: 'keep until profile/preset cleanup unifies resolver semantics',
      notes: ['Profile and node presets are managed Host inputs, not direct-run inputs.'],
    });
  }

  if (
    normalized.includes('/deployments/environments/')
    || normalized.startsWith('deployments/environments/')
    || normalized.includes('/deployments/topologies/')
    || normalized.startsWith('deployments/topologies/')
    || normalized.endsWith('/deployments/schema.json')
    || normalized === 'deployments/schema.json'
    || normalized.includes('/packages/') && normalized.includes('-deployment/')
    || normalized.startsWith('packages/') && normalized.includes('-deployment/')
  ) {
    return classification({
      kind: 'deletion-candidate',
      owner: 'Historical deployment layer',
      authoredBy: 'historical deployment tooling',
      directRunReads: false,
      managedHostReads: false,
      generated: false,
      recommendedAction: 'delete only after grep/test proof shows no live reader',
      notes: ['This path matches Phase 6 deletion candidates.'],
    });
  }

  if (
    basename === 'docker-compose.yml'
    || basename === 'Dockerfile'
    || normalized.includes('/systemd/')
    || normalized.includes('/native-dist/')
  ) {
    return classification({
      kind: 'platform-deployment',
      owner: 'Platform operator',
      authoredBy: 'operator or release engineer',
      directRunReads: false,
      managedHostReads: false,
      generated: false,
      recommendedAction: 'treat as deployment packaging, not package/runtime config',
      notes: ['Platform deployment files sit outside direct and managed package execution.'],
    });
  }

  return classification({
    kind: 'unknown',
    owner: 'unknown',
    authoredBy: 'unknown',
    directRunReads: false,
    managedHostReads: false,
    generated: false,
    recommendedAction: 'inspect before changing; add a classifier case if this becomes a recurring config path',
    notes: ['No current config simplification rule matched this path.'],
  });
}

function classification(
  result: Omit<IConfigExplainResult, 'path' | 'relativePath' | 'exists'>,
): Omit<IConfigExplainResult, 'path' | 'relativePath' | 'exists'> {
  return result;
}

function normalizePath(value: string): string {
  return value.replace(/\\/g, '/');
}
