/*
Copyright (c) 2019-2023 Digital Energy Cloud Solutions LLC. All Rights Reserved.
Authors:
Petr Krutov, <petr.krutov@digitalenergy.online>
Stanislav Solovev, <spsolovev@digitalenergy.online>
Sergey Kisil, <svkisil@digitalenergy.online>

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.
*/

/*
Terraform DECORT provider - manage resources provided by DECORT (Digital Energy Cloud
Orchestration Technology) with Terraform by Hashicorp.

Source code: https://repository.basistech.ru/BASIS/terraform-provider-decort

Please see README.md to learn where to place source code so that it
builds seamlessly.

Documentation: https://repository.basistech.ru/BASIS/terraform-provider-decort/wiki
*/

package vins

import (
	"context"
	"strconv"

	log "github.com/sirupsen/logrus"
	"repository.basistech.ru/BASIS/decort-golang-sdk/pkg/cloudbroker/vins"
	"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"
	"repository.basistech.ru/BASIS/terraform-provider-decort/internal/status"

	"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
	"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceVinsCreate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
	log.Debugf("resourceVinsCreate: called for ViNS name %s, Account ID %d, RG ID %d",
		d.Get("name").(string), d.Get("account_id").(int), d.Get("rg_id").(int))

	c := m.(*controller.ControllerCfg)

	RGID, rgOk := d.GetOk("rg_id")
	AccountID, accountIdOk := d.GetOk("account_id")

	if !rgOk && !accountIdOk {
		return diag.Errorf("resourceVinsCreate: no valid accountId or resource group ID specified")
	}

	if rgOk && accountIdOk {
		return diag.Errorf("resourceVinsCreate: either accountId or resource group ID should be specified")
	}

	var vinsID uint64
	if accountIdOk {
		req, diags := createVinsInAcc(ctx, d, m, uint64(AccountID.(int)))
		if diags != nil {
			return diags
		}

		apiResp, err := c.CloudBroker().VINS().CreateInAccount(ctx, req)
		if err != nil {
			d.SetId("")
			return diag.FromErr(err)
		}

		vinsID = apiResp
	} else if rgOk {
		req, diags := createVinsInRG(ctx, d, m, uint64(RGID.(int)))
		if diags != nil {
			return diags
		}

		apiResp, err := c.CloudBroker().VINS().CreateInRG(ctx, req)
		if err != nil {
			d.SetId("")
			return diag.FromErr(err)
		}

		vinsID = apiResp
	}

	d.SetId(strconv.FormatUint(vinsID, 10))
	d.Set("vins_id", vinsID)

	log.Debugf("resourceVinsCreate: new ViNS ID / name %d / %s creation sequence complete", vinsID, d.Get("name").(string))

	warnings := dc.Warnings{}
	if _, ok := d.GetOk("ip"); ok {
		if errs := resourceVinsIpReserve(ctx, d, m, vinsID); len(errs) != 0 {
			for _, err := range errs {
				warnings.Add(err)
			}
		}
	}

	if _, ok := d.GetOk("nat_rule"); ok {
		if errs := resourceVinsNatRuleAdd(ctx, d, m, vinsID); len(errs) != 0 {
			for _, err := range errs {
				warnings.Add(err)
			}
		}
	}

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

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

	warnings := dc.Warnings{}

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

	isEnabled := d.Get("enable").(bool)

	hasChangeState := false

	switch vinsData.Status {
	case status.Destroyed:
		d.Set("vins_id", 0)
		d.SetId("")
		return diag.Errorf("The resource cannot be read because it has been destroyed")
		// return resourceVinsCreate(ctx, d, m)
	case status.Deleted:
		// hasChangeState = true

		// req := vins.RestoreRequest{
		// 	VINSID: vinsData.ID,
		// }
		// if reason, ok := d.GetOk("reason"); ok {
		// 	req.Reason = reason.(string)
		// }

		// _, err := c.CloudBroker().VINS().Restore(ctx, req)
		// if err != nil {
		// 	warnings.Add(err)
		// }
	case status.Modeled:
		return diag.Errorf("ViNS are in status: %s, please, contact support for more information", vinsData.Status)
	case status.Created:
	case status.Enabled:
		if !isEnabled {
			hasChangeState = true
			if err := resourceVinsDisable(ctx, d, m, vinsData.ID); err != nil {
				warnings.Add(err)
			}
		}
	case status.Enabling:
	case status.Disabled:
		if isEnabled {
			hasChangeState = true
			if err := resourceVinsEnable(ctx, d, m, vinsData.ID); err != nil {
				warnings.Add(err)
			}
		}
	case status.Disabling:
	case status.Deleting:
		return diag.Errorf("ViNS are in progress with status: %s", vinsData.Status)
	}

	if hasChangeState {
		vinsData, err = utilityVinsCheckPresence(ctx, d, m)
		if vinsData == nil {
			d.SetId("")
			return diag.FromErr(err)
		}
	}

	flattenVins(d, vinsData)

	log.Debugf("resourceVinsRead: after flattenVins: vins_id %s, name %s",
		d.Id(), d.Get("name").(string))

	return warnings.Get()
}

func resourceVinsUpdate(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
	log.Debugf("resourceVinsUpdate: called for ViNS ID / name %s / %s,  Account ID %d, RG ID %d",
		d.Id(), d.Get("name").(string), d.Get("account_id").(int), d.Get("rg_id").(int))

	c := m.(*controller.ControllerCfg)

	if diags := checkParamsExistenceUpdate(ctx, d, c); diags != nil {
		return diags
	}

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

	isEnabled := d.Get("enable").(bool)

	hasChangeState := false

	warnings := dc.Warnings{}
	switch vinsData.Status {
	case status.Destroyed:
		d.Set("vins_id", 0)
		d.SetId("")
		return diag.Errorf("The resource cannot be updated because it has been destroyed")
		// return resourceVinsCreate(ctx, d, m)
	case status.Deleted:
		hasChangeState = true

		if err := resourceVinsRestore(ctx, d, m, vinsData.ID); err != nil {
			warnings.Add(err)
		}
	case status.Modeled:
		return diag.Errorf("ViNS are in status: %s, please, contact support for more information", vinsData.Status)
	case status.Created:
	case status.Enabled:
		if !isEnabled {
			hasChangeState = true
			if err := resourceVinsDisable(ctx, d, m, vinsData.ID); err != nil {
				warnings.Add(err)
			}
		}
	case status.Enabling:
	case status.Disabled:
		if isEnabled {
			hasChangeState = true
			if err := resourceVinsEnable(ctx, d, m, vinsData.ID); err != nil {
				warnings.Add(err)
			}
		}
	case status.Disabling:
	case status.Deleting:
		return diag.Errorf("ViNS are in progress with status: %s", vinsData.Status)
	}

	if hasChangeState {
		vinsData, err = utilityVinsCheckPresence(ctx, d, m)
		if err != nil {
			d.SetId("")
			return diag.FromErr(err)
		}
	}

	if d.HasChanges("name", "desc", "enable_secgroups") {
		vinsID := uint64(d.Get("vins_id").(int))
		if err := utilityUpdateVINS(ctx, d, m, vinsID); err != nil {
			return diag.FromErr(err)
		}
	}

	if d.HasChange("enable") {
		if err := resourceVinsChangeEnabled(ctx, d, m); err != nil {
			warnings.Add(err)
		}
	}

	if d.HasChange("ext_net_id") {
		if err := resourceVinsChangeExtNetId(ctx, d, m); err != nil {
			return diag.FromErr(err)
		}
	}

	if d.HasChange("ip") {
		if errs := resourceVinsChangeIp(ctx, d, m); len(errs) != 0 {
			for _, err := range errs {
				warnings.Add(err)
			}
		}
	}
	if d.HasChange("nat_rule") {
		if errs := resourceVinsChangeNatRule(ctx, d, m); len(errs) != 0 {
			for _, err := range errs {
				warnings.Add(err)
			}
		}
	}

	if d.HasChange("dns") {
		if err := resourceVinsChangeDNS(ctx, d, m); err != nil {
			warnings.Add(err)
		}
	}

	if d.HasChange("default_qos") {
		if err := resourceVinsChangeDefaultQos(ctx, d, m); err != nil {
			warnings.Add(err)
		}
	}

	if d.HasChange("vnfdev_redeploy") {
		if err := resourceVinsChangeVnfRedeploy(ctx, d, m); err != nil {
			warnings.Add(err)
		}
	}

	if d.HasChange("vnfdev_restart") {
		if err := resourceVinsChangeVnfRestart(ctx, d, m); err != nil {
			warnings.Add(err)
		}
	}

	if d.HasChange("vnfdev_reset") {
		if err := resourceVinsChangeVnfReset(ctx, d, m); err != nil {
			warnings.Add(err)
		}
	}

	if d.HasChange("vnfdev_start") {
		if err := resourceVinsChangeVnfStartStop(ctx, d, m); err != nil {
			warnings.Add(err)
		}
	}

	if d.HasChange("zone_id") {
		if err := resourceVinsChangeZoneID(ctx, d, m); err != nil {
			warnings.Add(err)
		}
	}

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

func resourceVinsDelete(ctx context.Context, d *schema.ResourceData, m interface{}) diag.Diagnostics {
	log.Debugf("resourceVinsDelete: called for ViNS ID / name %s / %s, Account ID %d, RG ID %d",
		d.Id(), d.Get("name").(string), d.Get("account_id").(int), d.Get("rg_id").(int))

	c := m.(*controller.ControllerCfg)

	vinsItem, err := utilityVinsCheckPresence(ctx, d, m)
	if vinsItem == nil {
		d.SetId("")
		return diag.FromErr(err)
	}

	req := vins.DeleteRequest{VINSID: vinsItem.ID}

	if force, ok := d.GetOk("force"); ok {
		req.Force = force.(bool)
	}
	if permanently, ok := d.GetOk("permanently"); ok {
		req.Permanently = permanently.(bool)
	}

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

	d.SetId("")

	return nil
}

func resourceVinsEnable(ctx context.Context, d *schema.ResourceData, m interface{}, vinsId uint64) error {
	c := m.(*controller.ControllerCfg)

	req := vins.EnableRequest{
		VINSID: vinsId,
	}

	_, err := c.CloudBroker().VINS().Enable(ctx, req)
	return err
}

func resourceVinsDisable(ctx context.Context, d *schema.ResourceData, m interface{}, vinsId uint64) error {
	c := m.(*controller.ControllerCfg)

	req := vins.DisableRequest{
		VINSID: vinsId,
	}

	_, err := c.CloudBroker().VINS().Disable(ctx, req)
	return err
}

func resourceVinsRestore(ctx context.Context, d *schema.ResourceData, m interface{}, vinsId uint64) error {
	c := m.(*controller.ControllerCfg)

	req := vins.RestoreRequest{
		VINSID: vinsId,
	}

	_, err := c.CloudBroker().VINS().Restore(ctx, req)
	return err
}

func resourceVinsIpReserve(ctx context.Context, d *schema.ResourceData, m interface{}, vinsId uint64) []error {
	var errs []error
	c := m.(*controller.ControllerCfg)

	ipRes := d.Get("ip")

	ipsSlice := ipRes.([]interface{})
	for _, ipInterfase := range ipsSlice {
		ip := ipInterfase.(map[string]interface{})

		req := vins.IPReserveRequest{
			VINSID: vinsId,
			Type:   ip["type"].(string),
		}
		if ipAddr, ok := ip["ip_addr"]; ok {
			req.IPAddr = ipAddr.(string)
		}
		if macAddr, ok := ip["mac"]; ok {
			req.MAC = macAddr.(string)
		}
		if computeId, ok := ip["compute_id"]; ok {
			req.ComputeID = uint64(computeId.(int))
		}

		_, err := c.CloudBroker().VINS().IPReserve(ctx, req)
		if err != nil {
			errs = append(errs, err)
		}
	}
	return errs
}

func resourceVinsNatRuleAdd(ctx context.Context, d *schema.ResourceData, m interface{}, vinsId uint64) []error {
	var errs []error
	c := m.(*controller.ControllerCfg)

	natRule := d.Get("nat_rule")

	addedNatRules := natRule.([]interface{})
	if len(addedNatRules) > 0 {
		for _, natRuleInterface := range addedNatRules {
			natRule := natRuleInterface.(map[string]interface{})

			req := vins.NATRuleAddRequest{
				VINSID:       vinsId,
				IntIP:        natRule["int_ip"].(string),
				ExtPortStart: uint64(natRule["ext_port_start"].(int)),
			}

			if intPort, ok := natRule["int_port"]; ok {
				req.IntPort = uint64(intPort.(int))
			}
			if extPortEnd, ok := natRule["ext_port_end"]; ok {
				req.ExtPortEnd = uint64(extPortEnd.(int))
			}
			if proto, ok := natRule["proto"]; ok {
				req.Proto = proto.(string)
			}

			_, err := c.CloudBroker().VINS().NATRuleAdd(ctx, req)
			if err != nil {
				errs = append(errs, err)
			}
		}
	}
	return errs
}

func resourceVinsChangeEnabled(ctx context.Context, d *schema.ResourceData, m interface{}) error {
	c := m.(*controller.ControllerCfg)
	vinsId := uint64(d.Get("vins_id").(int))

	_, enableNew := d.GetChange("enable")
	if enableNew.(bool) {
		req := vins.EnableRequest{
			VINSID: vinsId,
		}

		_, err := c.CloudBroker().VINS().Enable(ctx, req)
		return err
	}

	req := vins.DisableRequest{
		VINSID: vinsId,
	}

	_, err := c.CloudBroker().VINS().Disable(ctx, req)
	return err
}

func resourceVinsChangeExtNetId(ctx context.Context, d *schema.ResourceData, m interface{}) error {
	c := m.(*controller.ControllerCfg)

	vinsId := uint64(d.Get("vins_id").(int))
	oldExtNetId, newExtNedId := d.GetChange("ext_net_id")
	log.Debugf("resourceVinsUpdate - resourceVinsChangeExtNetId: changing ViNS ID %s - ext_net_id %d -> %d", d.Id(), oldExtNetId.(int), newExtNedId.(int))

	if oldExtNetId.(int) > 0 {
		// there was preexisting external net connection - disconnect ViNS
		req := vins.ExtNetDisconnectRequest{VINSID: vinsId}

		_, err := c.CloudBroker().VINS().ExtNetDisconnect(ctx, req)
		return err
	}

	if newExtNedId.(int) >= 0 {
		req := vins.ExtNetConnectRequest{
			VINSID: vinsId,
			NetID:  uint64(newExtNedId.(int)),
		}
		if ip, ok := d.GetOk("ext_ip"); ok && ip != "" {
			req.IP = ip.(string)
		}

		_, err := c.CloudBroker().VINS().ExtNetConnect(ctx, req)
		return err
	}

	return nil
}

func resourceVinsChangeIp(ctx context.Context, d *schema.ResourceData, m interface{}) []error {
	c := m.(*controller.ControllerCfg)

	var errs []error

	vinsId := uint64(d.Get("vins_id").(int))
	deletedIps := make([]interface{}, 0)
	addedIps := make([]interface{}, 0)

	oldIpInterface, newIpInterface := d.GetChange("ip")
	oldIpSlice := oldIpInterface.([]interface{})
	newIpSlice := newIpInterface.([]interface{})

	for _, el := range oldIpSlice {
		if !isContainsIp(newIpSlice, el) {
			deletedIps = append(deletedIps, el)
		}
	}

	for _, el := range newIpSlice {
		if !isContainsIp(oldIpSlice, el) {
			addedIps = append(addedIps, el)
		}
	}

	if len(deletedIps) > 0 {
		for _, ipInterface := range deletedIps {
			ip := ipInterface.(map[string]interface{})
			req := vins.IPReleaseRequest{VINSID: vinsId}

			if ip["ip_addr"].(string) != "" {
				req.IPAddr = ip["ip_addr"].(string)
			}
			if ip["mac"].(string) != "" {
				req.MAC = ip["mac"].(string)
			}

			_, err := c.CloudBroker().VINS().IPRelease(ctx, req)
			if err != nil {
				errs = append(errs, err)
			}
		}
	}

	if len(addedIps) > 0 {
		for _, ipInterface := range addedIps {
			ip := ipInterface.(map[string]interface{})
			req := vins.IPReserveRequest{
				VINSID: vinsId,
				Type:   ip["type"].(string),
			}

			if ip["ip_addr"].(string) != "" {
				req.IPAddr = ip["ip_addr"].(string)
			}
			if ip["mac"].(string) != "" {
				req.MAC = ip["mac"].(string)
			}
			if ip["compute_id"].(int) != 0 {
				req.ComputeID = uint64(ip["compute_id"].(int))
			}

			_, err := c.CloudBroker().VINS().IPReserve(ctx, req)
			if err != nil {
				errs = append(errs, err)
			}
		}
	}

	return errs
}

func resourceVinsChangeNatRule(ctx context.Context, d *schema.ResourceData, m interface{}) []error {
	c := m.(*controller.ControllerCfg)

	var errs []error

	vinsId := uint64(d.Get("vins_id").(int))

	deletedNatRules := make([]interface{}, 0)
	addedNatRules := make([]interface{}, 0)

	oldNatRulesInterface, newNatRulesInterface := d.GetChange("nat_rule")
	oldNatRulesSlice := oldNatRulesInterface.([]interface{})
	newNatRulesSlice := newNatRulesInterface.([]interface{})

	for _, el := range oldNatRulesSlice {
		if !isContainsNatRule(newNatRulesSlice, el) {
			deletedNatRules = append(deletedNatRules, el)
		}
	}

	for _, el := range newNatRulesSlice {
		if !isContainsNatRule(oldNatRulesSlice, el) {
			addedNatRules = append(addedNatRules, el)
		}
	}

	if len(deletedNatRules) > 0 {
		for _, natRuleInterface := range deletedNatRules {
			natRule := natRuleInterface.(map[string]interface{})
			req := vins.NATRuleDelRequest{
				VINSID: vinsId,
				RuleID: int64(natRule["rule_id"].(int)),
			}

			_, err := c.CloudBroker().VINS().NATRuleDel(ctx, req)
			errs = append(errs, err)
		}
	}

	if len(addedNatRules) > 0 {
		for _, natRuleInterface := range addedNatRules {
			natRule := natRuleInterface.(map[string]interface{})
			req := vins.NATRuleAddRequest{
				VINSID:       vinsId,
				IntIP:        natRule["int_ip"].(string),
				ExtPortStart: uint64(natRule["ext_port_start"].(int)),
			}

			if natRule["int_port"].(int) != 0 {
				req.IntPort = uint64(natRule["int_port"].(int))
			}
			if natRule["ext_port_end"].(int) != 0 {
				req.ExtPortEnd = uint64(natRule["ext_port_end"].(int))
			}
			if natRule["proto"].(string) != "" {
				req.Proto = natRule["proto"].(string)
			}

			_, err := c.CloudBroker().VINS().NATRuleAdd(ctx, req)
			if err != nil {
				errs = append(errs, err)
			}
		}
	}

	return errs
}

func resourceVinsChangeDNS(ctx context.Context, d *schema.ResourceData, m interface{}) error {
	c := m.(*controller.ControllerCfg)

	vinsId := uint64(d.Get("vins_id").(int))

	// empty "dns" is allowed, it will update vnfs.dhcp.config.dns from current values to empty list
	dnsInterface := d.Get("dns").(*schema.Set).List()
	dnsList := make([]string, 0, len(dnsInterface))
	for _, item := range dnsInterface {
		dnsList = append(dnsList, item.(string))
	}

	req := vins.DNSApplyRequest{
		VINSID:  vinsId,
		DNSList: dnsList,
	}

	_, err := c.CloudBroker().VINS().DNSApply(ctx, req)
	if err != nil {
		return err
	}

	return nil
}

func resourceVinsChangeDefaultQos(ctx context.Context, d *schema.ResourceData, m interface{}) error {
	c := m.(*controller.ControllerCfg)

	vinsId := uint64(d.Get("vins_id").(int))

	defaultQosInterface := d.Get("default_qos").([]interface{})

	if len(defaultQosInterface) > 0 {
		defaultQos := defaultQosInterface[0].(map[string]interface{})
		req := vins.DefaultQOSUpdateRequest{VINSID: vinsId}
		if inRate, ok := defaultQos["in_rate"]; ok {
			req.IngressRate = uint64(inRate.(int))
		}
		if inBurst, ok := defaultQos["in_burst"]; ok {
			req.IngressBirst = uint64(inBurst.(int))
		}
		if eRate, ok := defaultQos["e_rate"]; ok {
			req.EgressRate = uint64(eRate.(int))
		}

		_, err := c.CloudBroker().VINS().DefaultQOSUpdate(ctx, req)
		return err
	}

	return nil
}

func resourceVinsChangeVnfRedeploy(ctx context.Context, d *schema.ResourceData, m interface{}) error {
	c := m.(*controller.ControllerCfg)

	vinsId := uint64(d.Get("vins_id").(int))

	_, newRedeploy := d.GetChange("vnfdev_redeploy")
	if newRedeploy.(bool) {
		req := vins.VNFDevRedeployRequest{VINSID: vinsId}

		_, err := c.CloudBroker().VINS().VNFDevRedeploy(ctx, req)
		return err
	}

	return nil
}

func resourceVinsChangeVnfRestart(ctx context.Context, d *schema.ResourceData, m interface{}) error {
	c := m.(*controller.ControllerCfg)

	vinsId := uint64(d.Get("vins_id").(int))

	_, newRestart := d.GetChange("vnfdev_restart")
	if newRestart.(bool) {
		req := vins.VNFDevRestartRequest{VINSID: vinsId}

		_, err := c.CloudBroker().VINS().VNFDevRestart(ctx, req)
		if err != nil {
			return err
		}
	}

	return nil
}

func resourceVinsChangeVnfReset(ctx context.Context, d *schema.ResourceData, m interface{}) error {
	c := m.(*controller.ControllerCfg)

	vinsId := uint64(d.Get("vins_id").(int))

	_, newRestart := d.GetChange("vnfdev_reset")
	if newRestart.(bool) {
		req := vins.VNFDevResetRequest{VINSID: vinsId}

		_, err := c.CloudBroker().VINS().VNFDevReset(ctx, req)
		if err != nil {
			return err
		}
	}

	return nil
}

func resourceVinsChangeVnfStartStop(ctx context.Context, d *schema.ResourceData, m interface{}) error {
	c := m.(*controller.ControllerCfg)

	vinsId := uint64(d.Get("vins_id").(int))

	_, newStart := d.GetChange("vnfdev_start")
	if newStart.(bool) {
		req := vins.VNFDevStartRequest{VINSID: vinsId}

		_, err := c.CloudBroker().VINS().VNFDevStart(ctx, req)
		if err != nil {
			return err
		}
	}

	req := vins.VNFDevStopRequest{VINSID: vinsId}

	_, err := c.CloudBroker().VINS().VNFDevStop(ctx, req)
	return err
}

func resourceVinsChangeZoneID(ctx context.Context, d *schema.ResourceData, m interface{}) error {
	c := m.(*controller.ControllerCfg)

	vinsId := uint64(d.Get("vins_id").(int))
	zoneID := uint64(d.Get("zone_id").(int))

	req := vins.MigrateToZoneRequest{
		VINSID: vinsId,
		ZoneID: zoneID,
	}

	_, err := c.CloudBroker().VINS().MigrateToZone(ctx, req)
	return err
}

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

		CreateContext: resourceVinsCreate,
		ReadContext:   resourceVinsRead,
		UpdateContext: resourceVinsUpdate,
		DeleteContext: resourceVinsDelete,

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

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

		Schema: resourceVinsSchemaMake(),
	}
}
