package stpolicy

import (
	"context"
	"strconv"

	"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
	log "github.com/sirupsen/logrus"
	"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/stpolicy"
	"repository.basistech.ru/BASIS/terraform-provider-decort/internal/constants"
	"repository.basistech.ru/BASIS/terraform-provider-decort/internal/controller"
	"repository.basistech.ru/BASIS/terraform-provider-decort/internal/dc"
)

func resourceStoragePolicyCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
	log.Debugf("resourceTrunkCreate: called with name %s", d.Get("name").(string))

	c := m.(*controller.ControllerCfg)
	warnings := dc.Warnings{}

	name := d.Get("name").(string)
	aspRaw := d.Get("access_seps_pools")
	aspFromMan := aspRaw.(*schema.Set).List()
	aspArray := make([]stpolicy.AccessSEPsPool, 0, len(aspFromMan))
	aspMap := make(map[uint64][]string)
	for _, aspfm := range aspFromMan {
		temp := aspfm.(map[string]interface{})
		sepID := uint64(temp["sep_id"].(int))
		_, ok := aspMap[sepID]
		poolName := temp["pool_name"].(string)
		if !ok {
			aspMap[sepID] = []string{}
		}
		aspMap[sepID] = append(aspMap[sepID], poolName)
	}

	for key, value := range aspMap {
		asp := stpolicy.AccessSEPsPool{}
		asp.SEPID = key
		asp.PoolNames = value
		aspArray = append(aspArray, asp)
	}

	req := stpolicy.CreateRequest{
		Name:            name,
		AccessSEPsPools: aspArray,
	}

	if description, ok := d.GetOk("description"); ok {
		req.Description = description.(string)
	}

	if limitIOPS, ok := d.GetOk("limit_iops"); ok {
		req.LimitIOPS = uint64(limitIOPS.(int))
	}

	storagePolicyID, err := c.CloudBroker().StPolicy().Create(ctx, req)
	if err != nil {
		return diag.FromErr(err)
	}

	d.SetId(strconv.FormatUint(storagePolicyID, 10))

	if enabled, ok := d.GetOk("enabled"); ok {
		isToEnable := enabled.(bool)
		if err := handleStoragePolicyEnabling(ctx, d, c, storagePolicyID, isToEnable); err != nil {
			warnings.Add(err)
		}
	}

	return append(warnings.Get(), resourceStoragePolicyRead(ctx, d, m)...)
}

func resourceStoragePolicyRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
	log.Debugf("resourceStoragePolicyRead: called with name %s", d.Get("name").(string))

	w := dc.Warnings{}
	storagePolicyItem, err := utilityStoragePolicyCheckPresence(ctx, d, m)
	if err != nil {
		d.SetId("")
		return diag.FromErr(err)
	}

	flattenStoragePolicyResource(d, storagePolicyItem)

	return w.Get()
}

func resourceStoragePolicyUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
	storagePolicyID, _ := strconv.ParseUint(d.Id(), 10, 64)

	log.Debugf("resourceStoragePolicyUpdate: called storage policy with id %d", storagePolicyID)

	c := m.(*controller.ControllerCfg)

	_, err := utilityStoragePolicyCheckPresence(ctx, d, m)
	if err != nil {

		d.SetId("")

		return diag.FromErr(err)
	}

	_, err = strconv.ParseInt(d.Id(), 10, 64)
	if err != nil {

		d.SetId("")

		return diag.FromErr(err)
	}

	if d.HasChanges("name", "limit_iops", "description") {
		if err := utilityStoragePolicyHandleHasChanges(ctx, d, c, storagePolicyID); err != nil {
			return diag.FromErr(err)
		}
	}

	if d.HasChange("enabled") {
		enabled := d.Get("enabled")
		isToEnable := enabled.(bool)
		if err := handleStoragePolicyEnabling(ctx, d, c, storagePolicyID, isToEnable); err != nil {
			return diag.FromErr(err)
		}
	}

	if d.HasChange("access_seps_pools") {
		if err := utilityStoragePolicyUpdateAccessSEPsPools(ctx, d, c, storagePolicyID); err != nil {
			return diag.FromErr(err)
		}
	}
	return resourceStoragePolicyRead(ctx, d, m)
}

func resourceStoragePolicyDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
	log.Debugf("resourceStoragePolicyDelete: called with id %s", d.Id())

	storagePolicyItem, err := utilityStoragePolicyCheckPresence(ctx, d, m)
	if err != nil {

		d.SetId("")
		return diag.FromErr(err)
	}

	c := m.(*controller.ControllerCfg)
	req := stpolicy.DeleteRequest{
		StoragePolicyID: storagePolicyItem.ID,
	}
	if _, err := c.CloudBroker().StPolicy().Delete(ctx, req); err != nil {
		return diag.FromErr(err)
	}

	d.SetId("")

	return nil
}

func ResourceStoragePolicy() *schema.Resource {
	return &schema.Resource{
		SchemaVersion: 1,

		CreateContext: resourceStoragePolicyCreate,
		ReadContext:   resourceStoragePolicyRead,
		UpdateContext: resourceStoragePolicyUpdate,
		DeleteContext: resourceStoragePolicyDelete,

		Importer: &schema.ResourceImporter{
			StateContext: schema.ImportStatePassthroughContext,
		},

		Timeouts: &schema.ResourceTimeout{
			Create:  &constants.Timeout600s,
			Read:    &constants.Timeout600s,
			Update:  &constants.Timeout600s,
			Delete:  &constants.Timeout600s,
			Default: &constants.Timeout600s,
		},

		Schema: resourceStoragePolicySchemaMake(),
	}
}
