// 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"
	"iter"
	"net/http"
	"reflect"
)

func deleteDocumentConfigToMldev(fromObject map[string]any, parentObject map[string]any, rootObject map[string]any) (toObject map[string]any, err error) {
	toObject = make(map[string]any)

	fromForce := getValueByPath(fromObject, []string{"force"})
	if fromForce != nil {
		setValueByPath(parentObject, []string{"_query", "force"}, fromForce)
	}

	return toObject, nil
}

func deleteDocumentParametersToMldev(fromObject map[string]any, parentObject map[string]any, rootObject map[string]any) (toObject map[string]any, err error) {
	toObject = make(map[string]any)

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

	fromConfig := getValueByPath(fromObject, []string{"config"})
	if fromConfig != nil {
		_, err = deleteDocumentConfigToMldev(fromConfig.(map[string]any), toObject, rootObject)
		if err != nil {
			return nil, err
		}
	}

	return toObject, nil
}

func getDocumentParametersToMldev(fromObject map[string]any, parentObject map[string]any, rootObject map[string]any) (toObject map[string]any, err error) {
	toObject = make(map[string]any)

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

	return toObject, nil
}

func listDocumentsConfigToMldev(fromObject map[string]any, parentObject map[string]any, rootObject map[string]any) (toObject map[string]any, err error) {
	toObject = make(map[string]any)

	fromPageSize := getValueByPath(fromObject, []string{"pageSize"})
	if fromPageSize != nil {
		setValueByPath(parentObject, []string{"_query", "pageSize"}, fromPageSize)
	}

	fromPageToken := getValueByPath(fromObject, []string{"pageToken"})
	if fromPageToken != nil {
		setValueByPath(parentObject, []string{"_query", "pageToken"}, fromPageToken)
	}

	return toObject, nil
}

func listDocumentsParametersToMldev(fromObject map[string]any, parentObject map[string]any, rootObject map[string]any) (toObject map[string]any, err error) {
	toObject = make(map[string]any)

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

	fromConfig := getValueByPath(fromObject, []string{"config"})
	if fromConfig != nil {
		_, err = listDocumentsConfigToMldev(fromConfig.(map[string]any), toObject, rootObject)
		if err != nil {
			return nil, err
		}
	}

	return toObject, nil
}

func listDocumentsResponseFromMldev(fromObject map[string]any, parentObject map[string]any, rootObject map[string]any) (toObject map[string]any, err error) {
	toObject = make(map[string]any)

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

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

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

	return toObject, nil
}

type Documents struct {
	apiClient *apiClient
}

func (m Documents) Get(ctx context.Context, name string, config *GetDocumentConfig) (*Document, error) {
	parameterMap := make(map[string]any)

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

	var httpOptions *HTTPOptions
	if config == nil || config.HTTPOptions == nil {
		httpOptions = &HTTPOptions{}
	} else {
		httpOptions = config.HTTPOptions
	}
	if httpOptions.Headers == nil {
		httpOptions.Headers = http.Header{}
	}
	var response = new(Document)
	var responseMap map[string]any
	var toConverter func(map[string]any, map[string]any, map[string]any) (map[string]any, error)
	if m.apiClient.clientConfig.Backend == BackendVertexAI {

		return nil, fmt.Errorf("method Get is only supported in the Gemini Developer client. You can choose to use Gemini Developer client by setting ClientConfig.Backend to BackendGeminiAPI.")

	} else {
		toConverter = getDocumentParametersToMldev

	}

	body, err := toConverter(parameterMap, nil, parameterMap)
	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("None", urlParams)
	} else {
		path, err = formatMap("{name}", 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")
	}
	responseMap, err = sendRequest(ctx, m.apiClient, path, http.MethodGet, body, httpOptions)
	if err != nil {
		return nil, err
	}
	err = mapToStruct(responseMap, response)
	if err != nil {
		return nil, err
	}

	if field, ok := reflect.TypeOf(response).Elem().FieldByName("SDKHTTPResponse"); ok {
		{
			if reflect.ValueOf(response).Elem().FieldByName("SDKHTTPResponse").IsValid() {
				{
					reflect.ValueOf(response).Elem().FieldByName("SDKHTTPResponse").Set(reflect.Zero(field.Type))
				}
			}
		}
	}

	return response, nil
}

func (m Documents) Delete(ctx context.Context, name string, config *DeleteDocumentConfig) error {
	parameterMap := make(map[string]any)

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

	var httpOptions *HTTPOptions
	if config == nil || config.HTTPOptions == nil {
		httpOptions = &HTTPOptions{}
	} else {
		httpOptions = config.HTTPOptions
	}
	if httpOptions.Headers == nil {
		httpOptions.Headers = http.Header{}
	}
	var toConverter func(map[string]any, map[string]any, map[string]any) (map[string]any, error)
	if m.apiClient.clientConfig.Backend == BackendVertexAI {

		return fmt.Errorf("method Delete is only supported in the Gemini Developer client. You can choose to use Gemini Developer client by setting ClientConfig.Backend to BackendGeminiAPI.")

	} else {
		toConverter = deleteDocumentParametersToMldev

	}

	body, err := toConverter(parameterMap, nil, parameterMap)
	if err != nil {
		return 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("None", urlParams)
	} else {
		path, err = formatMap("{name}", urlParams)
	}
	if err != nil {
		return 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 err
		}
		path += "?" + query
		delete(body, "_query")
	}
	_, err = sendRequest(ctx, m.apiClient, path, http.MethodDelete, body, httpOptions)
	if err != nil {
		return err
	}

	return nil
}

func (m Documents) list(ctx context.Context, parent string, config *ListDocumentsConfig) (*ListDocumentsResponse, error) {
	parameterMap := make(map[string]any)

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

	var httpOptions *HTTPOptions
	if config == nil || config.HTTPOptions == nil {
		httpOptions = &HTTPOptions{}
	} else {
		httpOptions = config.HTTPOptions
	}
	if httpOptions.Headers == nil {
		httpOptions.Headers = http.Header{}
	}
	var response = new(ListDocumentsResponse)
	var responseMap map[string]any
	var fromConverter func(map[string]any, map[string]any, map[string]any) (map[string]any, error)
	var toConverter func(map[string]any, map[string]any, map[string]any) (map[string]any, error)
	if m.apiClient.clientConfig.Backend == BackendVertexAI {

		return nil, fmt.Errorf("method List is only supported in the Gemini Developer client. You can choose to use Gemini Developer client by setting ClientConfig.Backend to BackendGeminiAPI.")

	} else {
		toConverter = listDocumentsParametersToMldev
		fromConverter = listDocumentsResponseFromMldev
	}

	body, err := toConverter(parameterMap, nil, parameterMap)
	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("None", urlParams)
	} else {
		path, err = formatMap("{parent}/documents", 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")
	}
	responseMap, err = sendRequest(ctx, m.apiClient, path, http.MethodGet, body, httpOptions)
	if err != nil {
		return nil, err
	}
	if fromConverter != nil {
		responseMap, err = fromConverter(responseMap, nil, parameterMap)
	}
	if err != nil {
		return nil, err
	}
	err = mapToStruct(responseMap, response)
	if err != nil {
		return nil, err
	}

	if field, ok := reflect.TypeOf(response).Elem().FieldByName("SDKHTTPResponse"); ok {
		{
			if reflect.ValueOf(response).Elem().FieldByName("SDKHTTPResponse").IsValid() {
				{
					reflect.ValueOf(response).Elem().FieldByName("SDKHTTPResponse").Set(reflect.Zero(field.Type))
				}
			}
		}
	}

	return response, nil
}

// List retrieves a paginated list of documents resources.
func (m Documents) List(ctx context.Context, parent string, config *ListDocumentsConfig) (Page[Document], error) {
	listFunc := func(ctx context.Context, config map[string]any) ([]*Document, string, *HTTPResponse, error) {
		var c ListDocumentsConfig
		if err := mapToStruct(config, &c); err != nil {
			return nil, "", nil, err
		}
		resp, err := m.list(ctx, parent, &c)
		if err != nil {
			return nil, "", nil, err
		}
		return resp.Documents, resp.NextPageToken, resp.SDKHTTPResponse, nil
	}
	c := make(map[string]any)
	deepMarshal(config, &c)
	return newPage(ctx, "documents", c, listFunc)
}

// All retrieves all documents resources.
//
// This method handles pagination internally, making multiple API calls as needed
// to fetch all entries. It returns an iterator that yields each "documents"
// entry one by one. You do not need to manage pagination
// tokens or make multiple calls to retrieve all data.
func (m Documents) All(ctx context.Context, parent string) iter.Seq2[*Document, error] {
	listFunc := func(ctx context.Context, config map[string]any) ([]*Document, string, *HTTPResponse, error) {
		var c ListDocumentsConfig
		if err := mapToStruct(config, &c); err != nil {
			return nil, "", nil, err
		}
		resp, err := m.list(ctx, parent, &c)
		if err != nil {
			return nil, "", nil, err
		}
		return resp.Documents, resp.NextPageToken, resp.SDKHTTPResponse, nil
	}
	p, err := newPage(ctx, "documents", map[string]any{}, listFunc)
	if err != nil {
		return yieldErrorAndEndIterator[Document](err)
	}
	return p.all(ctx)
}
