package secgroup

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/secgroup"
	"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 resourceSecurityGroupCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
	log.Debugf("resourceSecurityGroupCreate: called with account ID %d, name %s", uint64(d.Get("account_id").(int)), d.Get("name").(string))

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

	accountID := uint64(d.Get("account_id").(int))
	name := d.Get("name").(string)

	req := secgroup.CreateRequest{
		AccountID: accountID,
		Name:      name,
	}

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

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

	d.SetId(strconv.FormatUint(securityGroupID, 10))
	d.Set("security_group_id", securityGroupID)

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

func resourceSecurityGroupRead(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
	log.Debugf("resourceSecurityGroupRead: called with with account ID %d", uint64(d.Get("account_id").(int)))

	w := dc.Warnings{}

	securityGroupItem, err := utilitySecurityGroupCheckPresence(ctx, d, m)
	if err != nil {
		d.SetId("")
		return diag.FromErr(err)
	}

	flattenSecurityGroupResource(d, securityGroupItem)

	return w.Get()
}

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

	log.Debugf("resourceSecurityGroupUpdate: called security group with id %d", securityGroupID)

	c := m.(*controller.ControllerCfg)

	_, err := utilitySecurityGroupCheckPresence(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", "description") {

		if err := utilitySecurityGroupHandleHasChanges(ctx, d, c, securityGroupID); err != nil {
			return diag.FromErr(err)
		}
	}

	if d.HasChange("rules") {
		if err := utilitySecurityGroupUpdateRules(ctx, d, c, securityGroupID); err != nil {
			return diag.FromErr(err)
		}
	}

	return resourceSecurityGroupRead(ctx, d, m)
}

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

	securityGroupItem, err := utilitySecurityGroupCheckPresence(ctx, d, m)
	if err != nil {

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

	c := m.(*controller.ControllerCfg)
	req := secgroup.DeleteRequest{
		SecurityGroupID: securityGroupItem.ID,
	}
	if _, err := c.CloudBroker().SecurityGroup().Delete(ctx, req); err != nil {
		return diag.FromErr(err)
	}

	d.SetId("")

	return nil
}

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

		CreateContext: resourceSecurityGroupCreate,
		ReadContext:   resourceSecurityGroupRead,
		UpdateContext: resourceSecurityGroupUpdate,
		DeleteContext: resourceSecurityGroupDelete,

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