// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
import { UsageFlags, } from "@azure-tools/typespec-client-generator-core";
import { NoTarget } from "@typespec/compiler";
import { InputOperationParameterKind } from "../type/input-operation-parameter-kind.js";
import { RequestLocation } from "../type/request-location.js";
import { navigateModels } from "./model.js";
import { fromSdkServiceMethod, getParameterDefaultValue } from "./operation-converter.js";
import { processServiceAuthentication } from "./service-authentication.js";
import { fromSdkType } from "./type-converter.js";
/**
 * Creates the code model from the SDK context.
 * @param sdkContext - The SDK context
 * @returns The code model
 * @beta
 */
export function createModel(sdkContext) {
    const sdkPackage = sdkContext.sdkPackage;
    navigateModels(sdkContext);
    const sdkApiVersionEnums = sdkPackage.enums.filter((e) => e.usage === UsageFlags.ApiVersionEnum);
    const rootClients = sdkPackage.clients.filter((c) => c.initialization.access === "public");
    if (rootClients.length === 0) {
        sdkContext.logger.reportDiagnostic({
            code: "no-root-client",
            format: {},
            target: NoTarget,
        });
        return {};
    }
    const rootApiVersions = sdkApiVersionEnums.length > 0
        ? sdkApiVersionEnums[0].values.map((v) => v.value).flat()
        : rootClients[0].apiVersions;
    const inputClients = [];
    fromSdkClients(rootClients, inputClients, []);
    const clientModel = {
        // rootNamespace is really coalescing the `package-name` option and the first namespace found.
        Name: sdkPackage.rootNamespace,
        ApiVersions: rootApiVersions,
        Enums: Array.from(sdkContext.__typeCache.enums.values()),
        Models: Array.from(sdkContext.__typeCache.models.values()),
        Clients: inputClients,
        Auth: processServiceAuthentication(sdkContext, sdkPackage),
    };
    return clientModel;
    function fromSdkClients(clients, inputClients, parentClientNames) {
        for (const client of clients) {
            const inputClient = fromSdkClient(client, parentClientNames);
            inputClients.push(inputClient);
            const subClients = client.methods
                .filter((m) => m.kind === "clientaccessor")
                .map((m) => m.response);
            parentClientNames.push(inputClient.Name);
            fromSdkClients(subClients, inputClients, parentClientNames);
            parentClientNames.pop();
        }
    }
    function fromSdkClient(client, parentNames) {
        const endpointParameter = client.initialization.properties.find((p) => p.kind === "endpoint");
        const uri = getMethodUri(endpointParameter);
        const clientParameters = fromSdkEndpointParameter(endpointParameter);
        const clientName = getClientName(client, parentNames);
        sdkContext.__typeCache.crossLanguageDefinitionIds.set(client.crossLanguageDefinitionId, client.__raw.type);
        return {
            Name: clientName,
            Namespace: client.namespace,
            Summary: client.summary,
            Doc: client.doc,
            Operations: client.methods
                .filter((m) => m.kind !== "clientaccessor")
                .map((m) => fromSdkServiceMethod(sdkContext, m, uri, rootApiVersions)),
            Protocol: {},
            Parent: parentNames.length > 0 ? parentNames[parentNames.length - 1] : undefined,
            Parameters: clientParameters,
            Decorators: client.decorators,
            CrossLanguageDefinitionId: client.crossLanguageDefinitionId,
        };
    }
    function getClientName(client, parentClientNames) {
        const clientName = client.name;
        if (parentClientNames.length === 0)
            return clientName;
        if (parentClientNames.length >= 2)
            return `${parentClientNames.slice(parentClientNames.length - 1).join("")}${clientName}`;
        return clientName;
    }
    function fromSdkEndpointParameter(p) {
        if (p.type.kind === "union") {
            return fromSdkEndpointType(p.type.variantTypes[0]);
        }
        else {
            return fromSdkEndpointType(p.type);
        }
    }
    function fromSdkEndpointType(type) {
        // TODO: support free-style endpoint url with multiple parameters
        const endpointExpr = type.serverUrl
            .replace("https://", "")
            .replace("http://", "")
            .split("/")[0];
        if (!/^\{\w+\}$/.test(endpointExpr)) {
            sdkContext.logger.reportDiagnostic({
                code: "unsupported-endpoint-url",
                format: { endpoint: type.serverUrl },
                target: NoTarget,
            });
            return [];
        }
        const endpointVariableName = endpointExpr.substring(1, endpointExpr.length - 1);
        const parameters = [];
        for (const parameter of type.templateArguments) {
            const isEndpoint = parameter.name === endpointVariableName;
            const parameterType = isEndpoint
                ? {
                    kind: "url",
                    name: "url",
                    crossLanguageDefinitionId: "TypeSpec.url",
                }
                : fromSdkType(sdkContext, parameter.type); // TODO: consolidate with converter.fromSdkEndpointType
            parameters.push({
                Name: parameter.name,
                NameInRequest: parameter.serializedName,
                Summary: parameter.summary,
                Doc: parameter.doc,
                // TODO: we should do the magic in generator
                Type: parameterType,
                Location: RequestLocation.Uri,
                IsApiVersion: parameter.isApiVersionParam,
                IsResourceParameter: false,
                IsContentType: false,
                IsRequired: !parameter.optional,
                IsEndpoint: isEndpoint,
                SkipUrlEncoding: false,
                Explode: false,
                Kind: InputOperationParameterKind.Client,
                DefaultValue: getParameterDefaultValue(sdkContext, parameter.clientDefaultValue, parameterType),
            });
        }
        return parameters;
    }
}
function getMethodUri(p) {
    if (!p)
        return "";
    if (p.type.kind === "endpoint" && p.type.templateArguments.length > 0)
        return p.type.serverUrl;
    if (p.type.kind === "union" && p.type.variantTypes.length > 0)
        return p.type.variantTypes[0].serverUrl;
    return `{${p.name}}`;
}
//# sourceMappingURL=client-model-builder.js.map