/*
 * Copyright 2026 Oleg Borodin <onborodin@gmail.com>
 *
 * This work is published and licensed under a Creative Commons
 * Attribution-NonCommercial-NoDerivatives 4.0 International License.
 *
 * Distribution of this work is permitted, but commercial use and
 * modifications are strictly prohibited.
 */
package client

import (
	"context"
	"encoding/json"
	"fmt"

	"mstore/app/handler"
	"mstore/app/operator"
	"mstore/pkg/descr"
)

func (cli *Client) CreateAccount(ctx context.Context, hosturi, username, password string) (string, error) {
	var err error
	var res string

	apiuri, err := setApiPath(hosturi, "/v3/api/account/create")
	if err != nil {
		return res, err
	}
	operParams := operator.CreateAccountParams{
		Username: username,
		Password: password,
	}
	paramsJson, err := json.Marshal(operParams)
	if err != nil {
		return res, err
	}
	respBytes, err := doHTTPCall(ctx, cli.skipTLSVerify, apiuri, paramsJson)
	if err != nil {
		return res, err
	}

	operRes := handler.NewResponse[operator.CreateAccountResult]()
	err = json.Unmarshal(respBytes, operRes)
	if err != nil {
		return res, err
	}
	if operRes.Error {
		err = fmt.Errorf("%s", operRes.Message)
		return res, err
	}
	res = operRes.Result.AccountID
	return res, err
}

func (cli *Client) GetAccountByID(ctx context.Context, hosturi, accountID string) (*descr.AccountShort, error) {
	var err error
	res := &descr.AccountShort{}

	apipath, err := setApiPath(hosturi, "/v3/api/account/get")
	if err != nil {
		return res, err
	}

	operParams := operator.GetAccountParams{
		AccountID: accountID,
	}
	paramsJson, err := json.Marshal(operParams)
	if err != nil {
		return res, err
	}
	respBytes, err := doHTTPCall(ctx, cli.skipTLSVerify, apipath, paramsJson)
	if err != nil {
		return res, err
	}

	operRes := handler.NewResponse[operator.GetAccountResult]()
	err = json.Unmarshal(respBytes, operRes)
	if err != nil {
		return res, err
	}
	if operRes.Error {
		err = fmt.Errorf("%s", operRes.Message)
		return res, err
	}
	res = operRes.Result.Account
	return res, err
}

func (cli *Client) GetAccountByName(ctx context.Context, hosturi, username string) (*descr.AccountShort, error) {
	var err error
	res := &descr.AccountShort{}

	apipath, err := setApiPath(hosturi, "/v3/api/account/get")
	if err != nil {
		return res, err
	}
	operParams := operator.GetAccountParams{
		Username: username,
	}
	paramsJson, err := json.Marshal(operParams)
	if err != nil {
		return res, err
	}
	respBytes, err := doHTTPCall(ctx, cli.skipTLSVerify, apipath, paramsJson)
	if err != nil {
		return res, err
	}

	operRes := handler.NewResponse[operator.GetAccountResult]()
	err = json.Unmarshal(respBytes, operRes)
	if err != nil {
		return res, err
	}
	if operRes.Error {
		err = fmt.Errorf("%s", operRes.Message)
		return res, err
	}
	res = operRes.Result.Account
	return res, err
}

func (cli *Client) UpdateAccountByID(ctx context.Context, hosturi string, accountID, newUsername, newPassword string) error {
	var err error

	apipath, err := setApiPath(hosturi, "/v3/api/account/update")
	if err != nil {
		return err
	}
	operParams := operator.UpdateAccountParams{
		AccountID:   accountID,
		NewUsername: newUsername,
		NewPassword: newPassword,
	}
	paramsJson, err := json.Marshal(operParams)
	if err != nil {
		return err
	}
	respBytes, err := doHTTPCall(ctx, cli.skipTLSVerify, apipath, paramsJson)
	if err != nil {
		return err
	}
	operRes := handler.NewResponse[operator.UpdateAccountResult]()
	err = json.Unmarshal(respBytes, operRes)
	if err != nil {
		return err
	}
	if operRes.Error {
		err = fmt.Errorf("%s", operRes.Message)
		return err
	}
	return err
}

func (cli *Client) UpdateAccountByName(ctx context.Context, hosturi, username, newUsername, newPassword string) error {
	var err error
	apipath, err := setApiPath(hosturi, "/v3/api/account/update")
	if err != nil {
		return err
	}
	operParams := operator.UpdateAccountParams{
		Username:    username,
		NewUsername: newUsername,
		NewPassword: newPassword,
	}
	paramsJson, err := json.Marshal(operParams)
	if err != nil {
		return err
	}
	respBytes, err := doHTTPCall(ctx, cli.skipTLSVerify, apipath, paramsJson)
	if err != nil {
		return err
	}
	operRes := handler.NewResponse[operator.UpdateAccountResult]()
	err = json.Unmarshal(respBytes, operRes)
	if err != nil {
		return err
	}
	if operRes.Error {
		err = fmt.Errorf("%s", operRes.Message)
		return err
	}
	return err
}

func (cli *Client) DeleteAccountByName(ctx context.Context, hosturi, username string) error {
	var err error

	apipath, err := setApiPath(hosturi, "/v3/api/account/delete")
	if err != nil {
		return err
	}
	operParams := operator.DeleteAccountParams{
		Username: username,
	}
	paramsJson, err := json.Marshal(operParams)
	if err != nil {
		return err
	}
	respBytes, err := doHTTPCall(ctx, cli.skipTLSVerify, apipath, paramsJson)
	if err != nil {
		return err
	}

	operRes := handler.NewResponse[operator.DeleteAccountResult]()
	err = json.Unmarshal(respBytes, operRes)
	if err != nil {
		return err
	}
	if operRes.Error {
		err = fmt.Errorf("%s", operRes.Message)
		return err
	}
	return err
}

func (cli *Client) DeleteAccountByID(ctx context.Context, hosturi, accountID string) error {
	var err error

	apipath, err := setApiPath(hosturi, "/v3/api/account/delete")
	if err != nil {
		return err
	}
	operParams := operator.DeleteAccountParams{
		AccountID: accountID,
	}
	paramsJson, err := json.Marshal(operParams)
	if err != nil {
		return err
	}
	respBytes, err := doHTTPCall(ctx, cli.skipTLSVerify, apipath, paramsJson)
	if err != nil {
		return err
	}

	operRes := handler.NewResponse[operator.DeleteAccountResult]()
	err = json.Unmarshal(respBytes, operRes)
	if err != nil {
		return err
	}
	if operRes.Error {
		err = fmt.Errorf("%s", operRes.Message)
		return err
	}
	return err
}

func (cli *Client) ListAccounts(ctx context.Context, hosturi string) ([]descr.AccountShort, error) {
	var err error
	res := make([]descr.AccountShort, 0)

	apipath, err := setApiPath(hosturi, "/v3/api/accounts/list")
	if err != nil {
		return res, err
	}
	operParams := operator.ListAccountsParams{}
	paramsJson, err := json.Marshal(operParams)
	if err != nil {
		return res, err
	}
	respBytes, err := doHTTPCall(ctx, cli.skipTLSVerify, apipath, paramsJson)
	if err != nil {
		return res, err
	}

	operRes := handler.NewResponse[operator.ListAccountsResult]()
	err = json.Unmarshal(respBytes, operRes)
	if err != nil {
		return res, err
	}
	if operRes.Error {
		err = fmt.Errorf("%s", operRes.Message)
		return res, err
	}
	res = operRes.Result.Accounts
	return res, err
}
