/**
 * Copyright (c) 2020-present, Goldman Sachs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { StoreProjectData } from './models/StoreProjectData.js';
import {
  DepotEntityWithOrigin,
  extractEntityNameFromPath,
  type EntitiesWithOrigin,
  type Entity,
} from '@finos/legend-storage';
import type { DepotServerClient } from './DepotServerClient.js';
import type { PlainObject } from '@finos/legend-shared';
import type { ProjectVersionEntities } from './models/ProjectVersionEntities.js';
import {
  LATEST_VERSION_ALIAS,
  SNAPSHOT_VERSION_ALIAS,
} from './DepotVersionAliases.js';
import { VersionedProjectData } from './models/VersionedProjectData.js';
import type { StoredSummaryEntity } from './models/StoredEntity.js';

export const retrieveProjectEntitiesWithDependencies = async (
  project: StoreProjectData,
  versionId: string,
  depotServerClient: DepotServerClient,
): Promise<Entity[]> => {
  const [entities, dependencyEntitiesIndex]: [
    PlainObject<Entity>[],
    Map<string, EntitiesWithOrigin>,
  ] = await Promise.all([
    depotServerClient.getEntities(project, versionId),
    depotServerClient.getIndexedDependencyEntities(project, versionId),
  ]);
  return Array.from(dependencyEntitiesIndex.values())
    .map((e) => e.entities)
    .flat()
    .concat(entities as unknown as Entity[]);
};

export const retrieveProjectEntitiesWithClassifier = async (
  project: StoreProjectData,
  versionId: string,
  classifier: string,
  depotServerClient: DepotServerClient,
): Promise<[PlainObject<Entity>[], PlainObject<Entity>[]]> => {
  const [entities, dependencyEntities]: [
    PlainObject<Entity>[],
    PlainObject<ProjectVersionEntities>[],
  ] = await Promise.all([
    depotServerClient.getEntities(project, versionId, classifier),
    depotServerClient.getDependencyEntities(
      project.groupId,
      project.artifactId,
      versionId,
      false,
      false,
      classifier,
    ),
  ]);

  return [
    entities,
    dependencyEntities.map((e) => e.entities).flat() as PlainObject<Entity>[],
  ];
};

export const projectIdHandlerFunc = async (
  groupId: string,
  artifactId: string,
  _versionId: string,
  depotServerClient: DepotServerClient,
  projectHandler: (projectId: string, resolvedVersion: string) => void,
): Promise<void> => {
  const project = StoreProjectData.serialization.fromJson(
    await depotServerClient.getProject(groupId, artifactId),
  );
  const versionId =
    _versionId === LATEST_VERSION_ALIAS
      ? VersionedProjectData.serialization.fromJson(
          await depotServerClient.getLatestVersion(groupId, artifactId),
        ).versionId
      : _versionId;
  projectHandler(project.projectId, versionId);
};

/**
 * Extract generic depot entity info (e.g., for DataProducts)
 * This preserves the actual classifierPath from the stored entity
 */
export const extractDepotEntityInfo = (
  storedEntity: StoredSummaryEntity,
  isSnapshot: boolean,
): DepotEntityWithOrigin =>
  new DepotEntityWithOrigin(
    {
      groupId: storedEntity.groupId,
      artifactId: storedEntity.artifactId,
      versionId: isSnapshot ? SNAPSHOT_VERSION_ALIAS : storedEntity.versionId,
    },
    extractEntityNameFromPath(storedEntity.path),
    storedEntity.path,
    storedEntity.classifierPath,
  );
