package trunk

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/trunk"
	"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 resourceTrunkCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {

	log.Debugf("resourceTrunkCreate: called with name %s, trunk_tags %s, ovs_bridge %s", d.Get("name").(string), d.Get("trunk_tags").(string), d.Get("ovs_bridge").(string))

	c := m.(*controller.ControllerCfg)

	warnings := dc.Warnings{}

	name := d.Get("name").(string)

	trunkTags := d.Get("trunk_tags").(string)

	ovsBridge := d.Get("ovs_bridge").(string)

	createReq := trunk.CreateRequest{
		Name:      name,
		TrunkTags: trunkTags,
		OVSBridge: ovsBridge,
	}

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

	if mtu, ok := d.GetOk("mtu"); ok {
		createReq.MTU = uint64(mtu.(int))
	}

	accountIDs := make([]uint64, 0)

	if accountAccess, ok := d.GetOk("account_ids"); ok {
		IDs := accountAccess.(*schema.Set).List()

		for _, ID := range IDs {
			accountIDs = append(accountIDs, uint64(ID.(int)))
		}
		createReq.AccountIDs = accountIDs
	}

	if nativeVLANID, ok := d.GetOk("native_vlan_id"); ok {
		createReq.NativeVLANID = uint64(nativeVLANID.(int))
	}

	trunkID, err := c.CloudBroker().Trunk().Create(ctx, createReq)
	if err != nil {
		return diag.FromErr(err)
	}

	d.SetId(strconv.FormatUint(trunkID, 10))
	d.Set("trunk_id", trunkID)

	if _, ok := d.GetOk("enable"); ok {
		if err := handleTrunkEnabling(ctx, d, c, trunkID); err != nil {
			warnings.Add(err)
		}
	}

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

func resourceTrunkRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {

	log.Debugf("resourceTrunkRead: called with name %s", d.Get("name").(string))

	w := dc.Warnings{}

	trunkItem, err := utilityTrunkCheckPresence(ctx, d, m)
	if err != nil {

		d.SetId("")

		return diag.FromErr(err)
	}
	flattenTrunkResource(d, trunkItem)

	return w.Get()
}

func resourceTrunkUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {

	log.Debugf("resourceTrunkUpdate: called with id %s", d.Id())
	c := m.(*controller.ControllerCfg)

	trunkItem, err := utilityTrunkCheckPresence(ctx, d, m)
	if err != nil {

		d.SetId("")

		return diag.FromErr(err)
	}

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

		d.SetId("")

		return diag.FromErr(err)
	}

	if d.HasChanges("name", "trunk_tags", "description", "native_vlan_id", "mtu") {
		req := trunk.UpdateRequest{
			TrunkID: uint64(id),
		}

		if d.HasChange("name") {
			name := d.Get("name").(string)
			req.Name = name
		}

		if d.HasChange("trunk_tags") {
			trunkTags := d.Get("trunk_tags").(string)
			req.TrunkTags = trunkTags
		}

		if d.HasChange("description") {
			description := d.Get("description").(string)
			req.Description = description
		}

		if d.HasChange("native_vlan_id") {
			nativeVLANID := uint64(d.Get("native_vlan_id").(int))
			req.NativeVLANID = nativeVLANID
		}

		if d.HasChange("mtu") {
			mtu := d.Get("mtu").(int)
			req.MTU = uint64(mtu)
		}

		if _, err := c.CloudBroker().Trunk().Update(ctx, req); err != nil {
			return diag.FromErr(err)
		}
	}

	if d.HasChange("enable") {
		if err := handleTrunkEnabling(ctx, d, c, uint64(id)); err != nil {
			return diag.FromErr(err)
		}
	}

	if d.HasChange("account_ids") {
		if err := handleAccountAccessUpdate(ctx, d, c, trunkItem); err != nil {
			return diag.FromErr(err)
		}
	}

	return resourceTrunkRead(ctx, d, m)
}

func resourceTrunkDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {

	log.Debugf("resourceTrunkDelete: called with id %s", d.Id())

	trunkItem, err := utilityTrunkCheckPresence(ctx, d, m)
	if err != nil {

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

	c := m.(*controller.ControllerCfg)

	req := trunk.DestroyRequest{
		TrunkID: trunkItem.ID,
	}

	_, err = c.CloudBroker().Trunk().Destroy(ctx, req)
	if err != nil {
		return diag.FromErr(err)
	}

	d.SetId("")

	return nil
}

func ResourceTrunk() *schema.Resource {
	return &schema.Resource{
		SchemaVersion: 2,

		CustomizeDiff: func(ctx context.Context, diff *schema.ResourceDiff, i interface{}) error {
			if diff.HasChanges() || diff.HasChanges("name", "trunk_tags", "description", "native_vlan_id", "account_ids") {
				diff.SetNewComputed("updated_time")
				diff.SetNewComputed("updated_by")
			}
			if diff.HasChanges("enable") {
				diff.SetNewComputed("status")
				diff.SetNewComputed("updated_time")
				diff.SetNewComputed("updated_by")
			}
			return nil
		},

		CreateContext: resourceTrunkCreate,
		ReadContext:   resourceTrunkRead,
		UpdateContext: resourceTrunkUpdate,
		DeleteContext: resourceTrunkDelete,

		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: resourceTrunkSchemaMake(),
	}
}
