export type TargetArtifactKind =
  | 'component'
  | 'canvas'
  | 'file'
  | 'repo'
  | 'package'
  | 'aggregate'
  | 'harness'
  | 'runtime'
  | 'unknown';

export interface TargetRef {
  readonly authorityRoot: string;
  readonly logicalMount: string;
  readonly artifactKind?: TargetArtifactKind;
  readonly classRef?: string;
  readonly instanceId?: string;
  readonly parentMount?: string;
}

export const TARGET_KEY_SEPARATOR = '\u001F';

export function normalizeAuthorityRoot(authorityRoot: string): string {
  const normalized = authorityRoot.trim().replace(/[/.]+$/u, '');
  if (!normalized) {
    throw new Error('TargetRef.authorityRoot is required');
  }
  return normalized;
}

export function normalizeLogicalMount(logicalMount: string): string {
  const normalized = logicalMount.trim().replace(/^[/.]+/u, '').replace(/[/.]+$/u, '');
  if (!normalized) {
    throw new Error('TargetRef.logicalMount is required');
  }
  return normalized;
}

export function canonicalTargetKey(ref: TargetRef): string {
  return [
    normalizeAuthorityRoot(ref.authorityRoot),
    normalizeLogicalMount(ref.logicalMount),
  ].join(TARGET_KEY_SEPARATOR);
}

export function isTargetRef(value: unknown): value is TargetRef {
  if (!value || typeof value !== 'object' || Array.isArray(value)) {
    return false;
  }
  const candidate = value as Partial<TargetRef>;
  return (
    typeof candidate.authorityRoot === 'string' &&
    candidate.authorityRoot.trim().length > 0 &&
    typeof candidate.logicalMount === 'string' &&
    candidate.logicalMount.trim().length > 0
  );
}
