import { isNonEmptyString, isRecord } from "./shared.js";
import { listAuthProfileSecretTargetEntries } from "./target-registry.js";

export type AuthProfileCredentialType = "api_key" | "token";

type AuthProfileFieldSpec = {
  valueField: string;
  refField: string;
};

type ApiKeyCredentialVisit = {
  kind: "api_key";
  profileId: string;
  provider: string;
  profile: Record<string, unknown>;
  valueField: string;
  refField: string;
  value: unknown;
  refValue: unknown;
};

type TokenCredentialVisit = {
  kind: "token";
  profileId: string;
  provider: string;
  profile: Record<string, unknown>;
  valueField: string;
  refField: string;
  value: unknown;
  refValue: unknown;
};

type OauthCredentialVisit = {
  kind: "oauth";
  profileId: string;
  provider: string;
  profile: Record<string, unknown>;
  hasAccess: boolean;
  hasRefresh: boolean;
};

export type AuthProfileCredentialVisit =
  | ApiKeyCredentialVisit
  | TokenCredentialVisit
  | OauthCredentialVisit;

function getAuthProfileFieldName(pathPattern: string): string {
  const segments = pathPattern.split(".").filter(Boolean);
  return segments[segments.length - 1] ?? "";
}

const AUTH_PROFILE_FIELD_SPEC_BY_TYPE = (() => {
  const defaults: Record<AuthProfileCredentialType, AuthProfileFieldSpec> = {
    api_key: { valueField: "key", refField: "keyRef" },
    token: { valueField: "token", refField: "tokenRef" },
  };
  for (const target of listAuthProfileSecretTargetEntries()) {
    if (!target.authProfileType) {
      continue;
    }
    defaults[target.authProfileType] = {
      valueField: getAuthProfileFieldName(target.pathPattern),
      refField:
        target.refPathPattern !== undefined
          ? getAuthProfileFieldName(target.refPathPattern)
          : defaults[target.authProfileType].refField,
    };
  }
  return defaults;
})();

export function getAuthProfileFieldSpec(type: AuthProfileCredentialType): AuthProfileFieldSpec {
  return AUTH_PROFILE_FIELD_SPEC_BY_TYPE[type];
}

export function* iterateAuthProfileCredentials(
  profiles: Record<string, unknown>,
): Iterable<AuthProfileCredentialVisit> {
  for (const [profileId, value] of Object.entries(profiles)) {
    if (!isRecord(value) || !isNonEmptyString(value.provider)) {
      continue;
    }
    const provider = String(value.provider);
    if (value.type === "api_key") {
      const spec = getAuthProfileFieldSpec("api_key");
      yield {
        kind: "api_key",
        profileId,
        provider,
        profile: value,
        valueField: spec.valueField,
        refField: spec.refField,
        value: value[spec.valueField],
        refValue: value[spec.refField],
      };
      continue;
    }
    if (value.type === "token") {
      const spec = getAuthProfileFieldSpec("token");
      yield {
        kind: "token",
        profileId,
        provider,
        profile: value,
        valueField: spec.valueField,
        refField: spec.refField,
        value: value[spec.valueField],
        refValue: value[spec.refField],
      };
      continue;
    }
    if (value.type === "oauth") {
      yield {
        kind: "oauth",
        profileId,
        provider,
        profile: value,
        hasAccess: isNonEmptyString(value.access),
        hasRefresh: isNonEmptyString(value.refresh),
      };
    }
  }
}
