package ecs

import (
	"context"
	"errors"
	"fmt"
	"time"

	"github.com/denverdino/aliyungo/common"
	"github.com/denverdino/aliyungo/ecs"
	"github.com/hashicorp/packer/helper/multistep"
	"github.com/hashicorp/packer/packer"
)

type stepConfigAlicloudVPC struct {
	VpcId     string
	CidrBlock string //192.168.0.0/16 or 172.16.0.0/16 (default)
	VpcName   string
	isCreate  bool
}

func (s *stepConfigAlicloudVPC) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
	config := state.Get("config").(*Config)
	client := state.Get("client").(*ecs.Client)
	ui := state.Get("ui").(packer.Ui)

	if len(s.VpcId) != 0 {
		vpcs, _, err := client.DescribeVpcs(&ecs.DescribeVpcsArgs{
			VpcId:    s.VpcId,
			RegionId: common.Region(config.AlicloudRegion),
		})
		if err != nil {
			ui.Say(fmt.Sprintf("Failed querying vpcs: %s", err))
			state.Put("error", err)
			return multistep.ActionHalt
		}
		if len(vpcs) > 0 {
			vpc := vpcs[0]
			state.Put("vpcid", vpc.VpcId)
			s.isCreate = false
			return multistep.ActionContinue
		}
		message := fmt.Sprintf("The specified vpc {%s} doesn't exist.", s.VpcId)
		state.Put("error", errors.New(message))
		ui.Say(message)
		return multistep.ActionHalt

	}
	ui.Say("Creating vpc")
	vpc, err := client.CreateVpc(&ecs.CreateVpcArgs{
		RegionId:  common.Region(config.AlicloudRegion),
		CidrBlock: s.CidrBlock,
		VpcName:   s.VpcName,
	})
	if err != nil {
		state.Put("error", err)
		ui.Say(fmt.Sprintf("Failed creating vpc: %s", err))
		return multistep.ActionHalt
	}
	err = client.WaitForVpcAvailable(common.Region(config.AlicloudRegion), vpc.VpcId, ALICLOUD_DEFAULT_SHORT_TIMEOUT)
	if err != nil {
		state.Put("error", err)
		ui.Say(fmt.Sprintf("Failed waiting for vpc to become available: %s", err))
		return multistep.ActionHalt
	}

	state.Put("vpcid", vpc.VpcId)
	s.isCreate = true
	s.VpcId = vpc.VpcId
	return multistep.ActionContinue
}

func (s *stepConfigAlicloudVPC) Cleanup(state multistep.StateBag) {
	if !s.isCreate {
		return
	}

	client := state.Get("client").(*ecs.Client)
	ui := state.Get("ui").(packer.Ui)

	message(state, "VPC")
	timeoutPoint := time.Now().Add(60 * time.Second)
	for {
		if err := client.DeleteVpc(s.VpcId); err != nil {
			e, _ := err.(*common.Error)
			if (e.Code == "DependencyViolation.Instance" || e.Code == "DependencyViolation.RouteEntry" ||
				e.Code == "DependencyViolation.VSwitch" ||
				e.Code == "DependencyViolation.SecurityGroup" ||
				e.Code == "Forbbiden") && time.Now().Before(timeoutPoint) {
				time.Sleep(1 * time.Second)
				continue
			}
			ui.Error(fmt.Sprintf("Error deleting vpc, it may still be around: %s", err))
			return
		}
		break
	}
}
