// Copyright 2025 Google LLC
//
// 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.

// Code generated by the Google Gen AI SDK generator DO NOT EDIT.

package genai

import (
	"context"
	"fmt"
	"net/http"
	"strings"
)

func getOperationParametersToMldev(ac *apiClient, fromObject map[string]any, parentObject map[string]any) (toObject map[string]any, err error) {
	toObject = make(map[string]any)

	fromOperationName := getValueByPath(fromObject, []string{"operationName"})
	if fromOperationName != nil {
		setValueByPath(toObject, []string{"_url", "operationName"}, fromOperationName)
	}

	fromConfig := getValueByPath(fromObject, []string{"config"})
	if fromConfig != nil {
		setValueByPath(toObject, []string{"config"}, fromConfig)
	}

	return toObject, nil
}

func getOperationParametersToVertex(ac *apiClient, fromObject map[string]any, parentObject map[string]any) (toObject map[string]any, err error) {
	toObject = make(map[string]any)

	fromOperationName := getValueByPath(fromObject, []string{"operationName"})
	if fromOperationName != nil {
		setValueByPath(toObject, []string{"_url", "operationName"}, fromOperationName)
	}

	fromConfig := getValueByPath(fromObject, []string{"config"})
	if fromConfig != nil {
		setValueByPath(toObject, []string{"config"}, fromConfig)
	}

	return toObject, nil
}

func fetchPredictOperationParametersToVertex(ac *apiClient, fromObject map[string]any, parentObject map[string]any) (toObject map[string]any, err error) {
	toObject = make(map[string]any)

	fromOperationName := getValueByPath(fromObject, []string{"operationName"})
	if fromOperationName != nil {
		setValueByPath(toObject, []string{"operationName"}, fromOperationName)
	}

	fromResourceName := getValueByPath(fromObject, []string{"resourceName"})
	if fromResourceName != nil {
		setValueByPath(toObject, []string{"_url", "resourceName"}, fromResourceName)
	}

	fromConfig := getValueByPath(fromObject, []string{"config"})
	if fromConfig != nil {
		setValueByPath(toObject, []string{"config"}, fromConfig)
	}

	return toObject, nil
}

// Operations provides methods for managing the long-running operations.
// You don't need to initiate this struct. Create a client instance via NewClient, and
// then access Operations through client.Operations field.
type Operations struct {
	apiClient *apiClient
}

func (m Operations) getVideosOperation(ctx context.Context, operationName string, config *GetOperationConfig) (*GenerateVideosOperation, error) {
	parameterMap := make(map[string]any)

	kwargs := map[string]any{"operationName": operationName, "config": config}
	deepMarshal(kwargs, &parameterMap)

	var httpOptions *HTTPOptions
	if config == nil {
		httpOptions = mergeHTTPOptions(m.apiClient.clientConfig, nil)
	} else {
		httpOptions = mergeHTTPOptions(m.apiClient.clientConfig, config.HTTPOptions)
		config.HTTPOptions = nil
	}
	var response = new(GenerateVideosOperation)
	var responseMap map[string]any
	var fromConverter func(*apiClient, map[string]any, map[string]any) (map[string]any, error)
	var toConverter func(*apiClient, map[string]any, map[string]any) (map[string]any, error)
	if m.apiClient.clientConfig.Backend == BackendVertexAI {
		toConverter = getOperationParametersToVertex
		fromConverter = generateVideosOperationFromVertex
	} else {
		toConverter = getOperationParametersToMldev
		fromConverter = generateVideosOperationFromMldev
	}

	body, err := toConverter(m.apiClient, parameterMap, nil)
	if err != nil {
		return nil, err
	}
	var path string
	var urlParams map[string]any
	if _, ok := body["_url"]; ok {
		urlParams = body["_url"].(map[string]any)
		delete(body, "_url")
	}
	if m.apiClient.clientConfig.Backend == BackendVertexAI {
		path, err = formatMap("{operationName}", urlParams)
	} else {
		path, err = formatMap("{operationName}", urlParams)
	}
	if err != nil {
		return nil, fmt.Errorf("invalid url params: %#v.\n%w", urlParams, err)
	}
	if _, ok := body["_query"]; ok {
		query, err := createURLQuery(body["_query"].(map[string]any))
		if err != nil {
			return nil, err
		}
		path += "?" + query
		delete(body, "_query")
	}

	if _, ok := body["config"]; ok {
		delete(body, "config")
	}
	responseMap, err = sendRequest(ctx, m.apiClient, path, http.MethodGet, body, httpOptions)
	if err != nil {
		return nil, err
	}
	responseMap, err = fromConverter(m.apiClient, responseMap, nil)
	if err != nil {
		return nil, err
	}
	err = mapToStruct(responseMap, response)
	if err != nil {
		return nil, err
	}
	return response, nil
}

func (m Operations) fetchPredictVideosOperation(ctx context.Context, operationName string, resourceName string, config *FetchPredictOperationConfig) (*GenerateVideosOperation, error) {
	parameterMap := make(map[string]any)

	kwargs := map[string]any{"operationName": operationName, "resourceName": resourceName, "config": config}
	deepMarshal(kwargs, &parameterMap)

	var httpOptions *HTTPOptions
	if config == nil {
		httpOptions = mergeHTTPOptions(m.apiClient.clientConfig, nil)
	} else {
		httpOptions = mergeHTTPOptions(m.apiClient.clientConfig, config.HTTPOptions)
		config.HTTPOptions = nil
	}
	var response = new(GenerateVideosOperation)
	var responseMap map[string]any
	var fromConverter func(*apiClient, map[string]any, map[string]any) (map[string]any, error)
	var toConverter func(*apiClient, map[string]any, map[string]any) (map[string]any, error)
	if m.apiClient.clientConfig.Backend == BackendVertexAI {
		toConverter = fetchPredictOperationParametersToVertex
		fromConverter = generateVideosOperationFromVertex
	} else {

		return nil, fmt.Errorf("method FetchPredictVideosOperation is only supported in the Vertex AI client. You can choose to use Vertex AI by setting ClientConfig.Backend to BackendVertexAI.")

	}

	body, err := toConverter(m.apiClient, parameterMap, nil)
	if err != nil {
		return nil, err
	}
	var path string
	var urlParams map[string]any
	if _, ok := body["_url"]; ok {
		urlParams = body["_url"].(map[string]any)
		delete(body, "_url")
	}
	if m.apiClient.clientConfig.Backend == BackendVertexAI {
		path, err = formatMap("{resourceName}:fetchPredictOperation", urlParams)
	} else {
		path, err = formatMap("None", urlParams)
	}
	if err != nil {
		return nil, fmt.Errorf("invalid url params: %#v.\n%w", urlParams, err)
	}
	if _, ok := body["_query"]; ok {
		query, err := createURLQuery(body["_query"].(map[string]any))
		if err != nil {
			return nil, err
		}
		path += "?" + query
		delete(body, "_query")
	}

	if _, ok := body["config"]; ok {
		delete(body, "config")
	}
	responseMap, err = sendRequest(ctx, m.apiClient, path, http.MethodPost, body, httpOptions)
	if err != nil {
		return nil, err
	}
	responseMap, err = fromConverter(m.apiClient, responseMap, nil)
	if err != nil {
		return nil, err
	}
	err = mapToStruct(responseMap, response)
	if err != nil {
		return nil, err
	}
	return response, nil
}

// GetVideosOperation retrieves the status and result of a long-running video generation operation.
//
// If the operation is still in progress, the returned GenerateVideosOperation
// will have Done set to false. If the operation has completed successfully,
// Done will be true, and the Result field will contain the result. If the
// operation failed, Done will be true, and the Error field will be populated.
func (m Operations) GetVideosOperation(ctx context.Context, operation *GenerateVideosOperation, config *GetOperationConfig) (*GenerateVideosOperation, error) {
	operationName := operation.Name
	if operationName == "" {
		return nil, fmt.Errorf("Operation name is empty")
	}
	if m.apiClient.clientConfig.Backend == BackendVertexAI {
		parts := strings.Split(operationName, "/operations/")
		if len(parts) > 1 {
			resourceName := parts[0]
			fetchPredictOperationConfig := &FetchPredictOperationConfig{}
			if config != nil {
				fetchPredictOperationConfig.HTTPOptions = config.HTTPOptions
			}
			return m.fetchPredictVideosOperation(ctx, operationName, resourceName, fetchPredictOperationConfig)
		} else {
			return nil, fmt.Errorf("Invalid operation name")
		}
	}
	return m.getVideosOperation(ctx, operationName, config)
}
