export interface IMountedInstanceSecretRefInput {
  readonly name?: string;
  readonly provider?: string;
  readonly ref?: string;
  readonly required?: boolean;
}

export interface IMountedInstanceMetadataInput {
  readonly id?: string;
  readonly packageName?: string;
  readonly packageRevision?: string;
  readonly class?: string;
  readonly mount?: string;
  readonly rootKind?: string;
  readonly componentType?: string;
  readonly configRef?: string;
  readonly secretRefs?: ReadonlyArray<IMountedInstanceSecretRefInput>;
  readonly dependsOn?: ReadonlyArray<string>;
  readonly policyRef?: string;
  readonly autoStart?: boolean;
}

export interface INormalizedMountedInstanceMetadata {
  readonly id?: string;
  readonly packageName?: string;
  readonly packageRevision?: string;
  readonly class?: string;
  readonly mount?: string;
  readonly rootKind?: string;
  readonly componentType?: string;
  readonly configRef?: string;
  readonly secretRefs?: ReadonlyArray<{
    readonly name: string;
    readonly provider: string;
    readonly ref: string;
    readonly required?: boolean;
  }>;
  readonly dependsOn?: ReadonlyArray<string>;
  readonly policyRef?: string;
  readonly autoStart: boolean;
}

export interface IResolvedMountedInstanceSpec<
  TRegistrationSource extends string = string,
> extends Omit<INormalizedMountedInstanceMetadata, 'id' | 'packageName' | 'class' | 'rootKind'> {
  readonly id: string;
  readonly packageName: string;
  readonly class: string;
  readonly rootKind: string;
  readonly registrationSource: TRegistrationSource;
}

export function trimToUndefined(value: unknown): string | undefined {
  if (typeof value !== 'string') return undefined;
  const trimmed = value.trim();
  return trimmed.length > 0 ? trimmed : undefined;
}

export function normalizeMountedInstanceMetadata(
  value: IMountedInstanceMetadataInput | null | undefined,
): INormalizedMountedInstanceMetadata {
  const secretRefs = normalizeSecretRefs(value?.secretRefs);
  const dependsOn = normalizeDependsOn(value?.dependsOn);

  return {
    ...(trimToUndefined(value?.componentType)
      ? { componentType: trimToUndefined(value?.componentType) }
      : {}),
    ...(trimToUndefined(value?.configRef)
      ? { configRef: trimToUndefined(value?.configRef) }
      : {}),
    ...(secretRefs.length > 0
      ? { secretRefs }
      : {}),
    ...(dependsOn.length > 0
      ? { dependsOn }
      : {}),
    ...(trimToUndefined(value?.policyRef)
      ? { policyRef: trimToUndefined(value?.policyRef) }
      : {}),
    autoStart: value?.autoStart === true,
  };
}

export function normalizeMountedInstanceSpec<
  TRegistrationSource extends string,
>(
  value: IMountedInstanceMetadataInput | null | undefined,
  options: {
    readonly registrationSource: TRegistrationSource;
    readonly packageRevision?: string;
    readonly mountRequired?: boolean;
  },
): IResolvedMountedInstanceSpec<TRegistrationSource> | null {
  const id = trimToUndefined(value?.id);
  const packageName = trimToUndefined(value?.packageName);
  const instanceClass = trimToUndefined(value?.class);
  const rootKind = trimToUndefined(value?.rootKind);
  const mount = trimToUndefined(value?.mount);
  if (!id || !packageName || !instanceClass || !rootKind) {
    return null;
  }
  if (options.mountRequired && !mount) {
    return null;
  }

  const metadata = normalizeMountedInstanceMetadata(value);
  return {
    id,
    packageName,
    ...(trimToUndefined(value?.packageRevision) ?? trimToUndefined(options.packageRevision)
      ? { packageRevision: trimToUndefined(value?.packageRevision) ?? trimToUndefined(options.packageRevision) }
      : {}),
    class: instanceClass,
    ...(mount ? { mount } : {}),
    rootKind,
    ...metadata,
    registrationSource: options.registrationSource,
  };
}

function normalizeSecretRefs(
  value: ReadonlyArray<IMountedInstanceSecretRefInput> | undefined,
): Array<{
  readonly name: string;
  readonly provider: string;
  readonly ref: string;
  readonly required?: boolean;
}> {
  if (!Array.isArray(value)) return [];
  const normalized: Array<{
    readonly name: string;
    readonly provider: string;
    readonly ref: string;
    readonly required?: boolean;
  }> = [];
  for (const entry of value) {
    const name = trimToUndefined(entry?.name);
    const provider = trimToUndefined(entry?.provider);
    const ref = trimToUndefined(entry?.ref);
    if (!name || !provider || !ref) continue;
    normalized.push({
      name,
      provider,
      ref,
      ...(entry?.required === true ? { required: true } : {}),
    });
  }
  return normalized;
}

function normalizeDependsOn(value: ReadonlyArray<string> | undefined): string[] {
  if (!Array.isArray(value)) return [];
  const seen = new Set<string>();
  const normalized: string[] = [];
  for (const entry of value) {
    const trimmed = trimToUndefined(entry);
    if (!trimmed || seen.has(trimmed)) continue;
    seen.add(trimmed);
    normalized.push(trimmed);
  }
  return normalized;
}
