package novuhandler

import (
	"strconv"
	"time"

	"github.com/google/uuid"

	"go.uber.org/zap"

	"github.com/pingcap/dbaas/billing2/utils/log"

	"github.com/pingcap/dbaas/billing2/forms"
)

func getPreferenceSettings() PreferenceSettings {
	return PreferenceSettings{
		Email: true,
		Sms:   true,
		InApp: true,
		Chat:  true,
		Push:  true,
	}
}
func getTriggers(TriggerID string) []Trigger {
	return []Trigger{
		{
			Type:       "event",
			Identifier: TriggerID,
			Variables: []Variable{{
				Name: "isSendNow",
				Type: "String",
			}},
		},
	}
}
func getTemplate() Template {
	return Template{
		Type:        "in_app",
		Active:      true,
		Subject:     "subject",
		Content:     "is null",
		ContentType: "editor",
	}
}
func getSteps() []Step {
	return []Step{
		{
			Active:           true,
			ShouldStopOnFail: false,
			Uuid:             uuid.NewString(),
			Name:             "Delay",
			Filters: []Filter{{
				Children: []FilterChildren{{
					Field:    "isSendNow",
					Value:    "false",
					Operator: "EQUAL",
					On:       "payload",
				},
				},
			}},
			Metadata: Metadata{
				DelayPath: "sendAt",
				Type:      "scheduled",
			},
			Template: Template{
				Type:        "delay",
				Active:      true,
				Content:     "",
				ContentType: "editor",
			},
		},
		{
			Active:           true,
			ShouldStopOnFail: false,
			Uuid:             uuid.NewString(),
			Name:             "In-App",
			Template:         getTemplate(),
			Metadata: Metadata{
				Type: "regular",
			},
		},
	}
}

func (m NovuHandlerImpl) GetWorkflowFromNovu(workFlowID string) (WorkFlow, error) {
	var res WorkFlow
	err := GetClient().Get("/v1/workflows/"+workFlowID, nil, &res)
	if err != nil {
		log.Error("GetWorkFlow error", zap.String("workFlowID", workFlowID), zap.Error(err))
		return res, err
	}

	return res, nil

}
func (m NovuHandlerImpl) GetWorkflowsFromNovu(page int, pageSize int) (Workflows, error) {
	var outPut Workflows
	input := map[string]string{"page": strconv.Itoa(page), "limit": strconv.Itoa(pageSize)}
	err := GetClient().Get("/v1/workflows/", input, &outPut)
	if err != nil {
		log.Error("GetWorkFlow error", zap.Error(err))
		return outPut, err
	}
	return outPut, nil
}
func (m NovuHandlerImpl) GetWorkflows(page int, pageSize int) (forms.WorkFlows, error) {
	res := forms.WorkFlows{}

	workflows, err := m.GetWorkflowsFromNovu(page, pageSize)
	if err != nil {
		return res, err
	}
	res.PageQuery.Page = page
	res.PageQuery.PageSize = pageSize
	res.Count = workflows.TotalCount
	for _, workflow := range workflows.Data {
		res.Workflows = append(res.Workflows, forms.Workflow{
			WorkFlowName: workflow.Name,
			WorkFlowID:   workflow.Id,
			TriggerID:    workflow.Triggers[0].Identifier,
			CreatorID:    workflow.CreatorId,
			CreatedAt:    workflow.CreatedAt,
			UpdatedAt:    workflow.UpdatedAt,
		})
	}
	return res, nil

}

func (m NovuHandlerImpl) CreateWorkflow(flow forms.Workflow) (forms.Workflow, error) {
	var outPut WorkFlow
	inPut := Data{}

	inPut.Id = flow.WorkFlowID
	inPut.Name = flow.WorkFlowName
	inPut.CreatorId = flow.CreatorID
	inPut.Description = flow.Subject
	inPut.Active = true
	inPut.Critical = true
	inPut.Draft = true
	notificationGroupID, err := m.GetNotificationGroupIDByName(flow.NotificationGroup)
	if err != nil {
		return forms.Workflow{}, err
	}
	inPut.NotificationGroupId = notificationGroupID

	inPut.PreferenceSettings = getPreferenceSettings()
	inPut.Triggers = getTriggers(flow.TriggerID)
	inPut.Steps = getSteps()
	if len(flow.InAppContent) > 0 {
		inPut.Steps[1].Template.Content = flow.InAppContent
	}
	if len(flow.Variables) > 0 {
		for _, v := range flow.Variables {
			inPut.Steps[1].Template.Variables = append(inPut.Steps[1].Template.Variables, Variable{
				Name: v.Name,
				Id:   v.Id,
				Type: v.Type,
			})
		}
	}

	log.Info("CreateWorkFlow ", zap.Any("flow", flow))
	err = GetClient().Request("POST", "/v1/workflows", nil, inPut, &outPut)
	if err != nil {
		log.Error("CreateWorkFlow error", zap.Error(err))
		return forms.Workflow{}, err

	}
	log.Info("CreateWorkFlow result  ", zap.Any("flow", outPut))
	flow.WorkFlowID = outPut.Data.Id
	flow.TriggerID = outPut.Data.Triggers[0].Identifier
	return flow, nil
}
func (m NovuHandlerImpl) UpdateWorkflow(flow forms.Workflow) (forms.Workflow, error) {
	outPut := WorkFlow{}
	input, err := m.GetWorkflowFromNovu(flow.WorkFlowID)
	input.Data.NotificationGroupId = input.Data.NotificationGroupId2

	if err != nil {
		return forms.Workflow{}, err
	}
	if len(flow.WorkFlowName) > 0 {
		input.Data.Name = flow.WorkFlowName
	}
	if len(flow.InAppContent) > 0 {
		input.Data.Steps[1].Template.Content = flow.InAppContent
	}
	if len(flow.Subject) > 0 {
		input.Data.Description = flow.Subject
	}
	if len(flow.NotificationGroup) > 0 {
		notificationGroupID, err := m.GetNotificationGroupIDByName(flow.NotificationGroup)
		if err != nil {
			return forms.Workflow{}, err
		}
		input.Data.NotificationGroupId = notificationGroupID

	}

	if len(flow.Variables) > 0 {
		for _, v := range flow.Variables {
			input.Data.Steps[1].Template.Variables = append(input.Data.Steps[1].Template.Variables, Variable{
				Name: v.Name,
				Id:   v.Id,
				Type: v.Type,
			})
		}
	}

	err = GetClient().Request("PUT", "/v1/workflows/"+flow.WorkFlowID, nil, input.Data, &outPut)
	if err != nil {
		return forms.Workflow{}, err
	}

	return flow, nil
}
func (m NovuHandlerImpl) DeleteWorkflow(flow forms.Workflow) error {

	return GetClient().Request("DELETE", "/v1/workflows/"+flow.WorkFlowID, nil, nil, nil)

}
func (m NovuHandlerImpl) GetWorkflow(workflowID string) (forms.Workflow, error) {
	res := forms.Workflow{}
	novuData, err := m.GetWorkflowFromNovu(workflowID)
	if err != nil {
		return res, err
	}
	groupName, err := m.GetNotificationGroupNameByID(novuData.Data.NotificationGroupId2)
	if err != nil {
		return res, err
	}
	res.NotificationGroup = groupName
	res.WorkFlowID = novuData.Data.Id
	res.WorkFlowName = novuData.Data.Name
	res.Subject = novuData.Data.Description
	res.TriggerID = novuData.Data.Triggers[0].Identifier
	res.InAppContent = novuData.Data.Steps[1].Template.Content
	for _, v := range novuData.Data.Steps[1].Template.Variables {
		res.Variables = append(res.Variables, forms.Variable{
			Name: v.Name,
			Id:   v.Id1,
			Type: v.Type,
		})
	}
	return res, nil
}
func (m NovuHandlerImpl) DuplicateWorkflow(workflowID string) (forms.Workflow, error) {
	res := forms.Workflow{}
	var outPut WorkFlow

	novuData, err := m.GetWorkflowFromNovu(workflowID)
	novuData.Data.NotificationGroupId = novuData.Data.NotificationGroupId2

	if err != nil {
		return res, nil
	}
	err = GetClient().Request("POST", "/v1/workflows", nil, novuData.Data, &outPut)
	if err != nil {
		log.Error("DuplicateWorkflow error", zap.Error(err))

	}
	log.Info("DuplicateWorkflow result  ", zap.Any("flow", outPut))
	res.WorkFlowName = outPut.Data.Name
	return res, nil
}

type Workflows struct {
	Page int `json:"page"`
	Data []struct {
		Id                  string        `json:"_id"`
		Name                string        `json:"name"`
		Type                string        `json:"type"`
		Active              bool          `json:"active"`
		Draft               bool          `json:"draft"`
		Critical            bool          `json:"critical"`
		IsBlueprint         bool          `json:"isBlueprint"`
		NotificationGroupId string        `json:"_notificationGroupId"`
		Tags                []interface{} `json:"tags"`
		Triggers            []struct {
			Type       string `json:"type"`
			Identifier string `json:"identifier"`
			Variables  []struct {
				Name string `json:"name"`
				Type string `json:"type"`
				Id   string `json:"_id"`
			} `json:"variables"`
			SubscriberVariables []struct {
				Name string `json:"name"`
				Id   string `json:"_id"`
			} `json:"subscriberVariables"`
			Id                string        `json:"_id"`
			ReservedVariables []interface{} `json:"reservedVariables,omitempty"`
		} `json:"triggers"`
		Steps []struct {
			Active           bool   `json:"active"`
			ShouldStopOnFail bool   `json:"shouldStopOnFail"`
			Uuid             string `json:"uuid"`
			Name             string `json:"name"`
			Filters          []struct {
				Children []interface{} `json:"children"`
				Id       string        `json:"_id"`
			} `json:"filters"`
			TemplateId string  `json:"_templateId"`
			ParentId   *string `json:"_parentId"`
			Metadata   struct {
				Timed struct {
					WeekDays  []interface{} `json:"weekDays"`
					MonthDays []interface{} `json:"monthDays"`
				} `json:"timed"`
				Amount        int         `json:"amount,omitempty"`
				Unit          string      `json:"unit,omitempty"`
				Type          string      `json:"type,omitempty"`
				BackoffAmount interface{} `json:"backoffAmount"`
				Backoff       bool        `json:"backoff,omitempty"`
			} `json:"metadata,omitempty"`
			Id       string `json:"_id"`
			Template struct {
				Id   string `json:"_id"`
				Type string `json:"type"`
			} `json:"template"`
			ReplyCallback struct {
				Active bool `json:"active"`
			} `json:"replyCallback,omitempty"`
		} `json:"steps"`
		PreferenceSettings struct {
			Email bool `json:"email"`
			Sms   bool `json:"sms"`
			InApp bool `json:"in_app"`
			Chat  bool `json:"chat"`
			Push  bool `json:"push"`
		} `json:"preferenceSettings"`
		EnvironmentId     string    `json:"_environmentId"`
		OrganizationId    string    `json:"_organizationId"`
		CreatorId         string    `json:"_creatorId"`
		Deleted           bool      `json:"deleted"`
		CreatedAt         time.Time `json:"createdAt"`
		UpdatedAt         time.Time `json:"updatedAt"`
		V                 int       `json:"__v"`
		NotificationGroup struct {
			Id             string    `json:"_id"`
			Name           string    `json:"name"`
			OrganizationId string    `json:"_organizationId"`
			EnvironmentId  string    `json:"_environmentId"`
			CreatedAt      time.Time `json:"createdAt"`
			UpdatedAt      time.Time `json:"updatedAt"`
			V              int       `json:"__v"`
		} `json:"notificationGroup"`
		WorkflowIntegrationStatus struct {
			HasActiveIntegrations bool `json:"hasActiveIntegrations"`
			Channels              struct {
				InApp struct {
					HasActiveIntegrations bool `json:"hasActiveIntegrations"`
				} `json:"in_app"`
				Email struct {
					HasActiveIntegrations  bool `json:"hasActiveIntegrations"`
					HasPrimaryIntegrations bool `json:"hasPrimaryIntegrations"`
				} `json:"email"`
				Sms struct {
					HasActiveIntegrations  bool `json:"hasActiveIntegrations"`
					HasPrimaryIntegrations bool `json:"hasPrimaryIntegrations"`
				} `json:"sms"`
				Chat struct {
					HasActiveIntegrations bool `json:"hasActiveIntegrations"`
				} `json:"chat"`
				Push struct {
					HasActiveIntegrations bool `json:"hasActiveIntegrations"`
				} `json:"push"`
			} `json:"channels"`
		} `json:"workflowIntegrationStatus"`
	} `json:"data"`
	TotalCount int `json:"totalCount"`
	PageSize   int `json:"pageSize"`
}
type PreferenceSettings struct {
	Email bool `json:"email"`
	Sms   bool `json:"sms"`
	InApp bool `json:"in_app"`
	Chat  bool `json:"chat"`
	Push  bool `json:"push"`
}
type FilterChildren struct {
	Field    string `json:"field"`
	Value    string `json:"value"`
	Operator string `json:"operator"`
	On       string `json:"on"`
}
type Filter struct {
	IsNegated bool             `json:"isNegated"`
	Type      string           `json:"type"`
	Value     string           `json:"value"`
	Children  []FilterChildren `json:"children"`
}

type Metadata struct {
	DelayPath string `json:"delayPath"`
	Type      string `json:"type"`
}

type ReplyCallback struct {
}
type Variable struct {
	Name     string `json:"name"`
	Type     string `json:"type"`
	Required bool   `json:"required"`
	Id       string `json:"_id"`
	Id1      string `json:"id"`
}
type Template struct {
	Id             string      `json:"_id"`
	Type           string      `json:"type"`
	Active         bool        `json:"active"`
	Title          string      `json:"title"`
	Subject        string      `json:"subject"`
	Variables      []Variable  `json:"variables"`
	Content        string      `json:"content"`
	ContentType    string      `json:"contentType"`
	EnvironmentId  string      `json:"_environmentId"`
	OrganizationId string      `json:"_organizationId"`
	CreatorId      string      `json:"_creatorId"`
	FeedId         interface{} `json:"_feedId"`
	LayoutId       interface{} `json:"_layoutId"`
	Deleted        bool        `json:"deleted"`
	CreatedAt      time.Time   `json:"createdAt"`
	UpdatedAt      time.Time   `json:"updatedAt"`
	V              int         `json:"__v"`
	Id1            string      `json:"id"`
}
type Step struct {
	Id               string        `json:"_id"`
	Uuid             string        `json:"uuid"`
	Name             string        `json:"name"`
	TemplateId       string        `json:"_templateId"`
	Active           bool          `json:"active"`
	ShouldStopOnFail bool          `json:"shouldStopOnFail"`
	Template         Template      `json:"template"`
	Filters          []Filter      `json:"filters"`
	Metadata         Metadata      `json:"metadata"`
	ReplyCallback    ReplyCallback `json:"replyCallback"`
}

type Trigger struct {
	Type                string                  `json:"type"`
	Identifier          string                  `json:"identifier"`
	Variables           []Variable              `json:"variables"`
	SubscriberVariables []struct{ Name string } `json:"subscriberVariables"`
}

type NotificationGroup struct {
	Id             string `json:"_id"`
	Name           string `json:"name"`
	EnvironmentId  string `json:"_environmentId"`
	OrganizationId string `json:"_organizationId"`
	ParentId       string `json:"_parentId"`
}

type Data struct {
	Id                 string             `json:"_id"`
	Name               string             `json:"name"`
	Description        string             `json:"description"`
	Active             bool               `json:"active"`
	Draft              bool               `json:"draft"`
	PreferenceSettings PreferenceSettings `json:"preferenceSettings"`
	Critical           bool               `json:"critical"`
	//Tags                []string           `json:"tags"`
	Steps                []Step    `json:"steps"`
	OrganizationId       string    `json:"_organizationId"`
	CreatorId            string    `json:"_creatorId"`
	EnvironmentId        string    `json:"_environmentId"`
	Triggers             []Trigger `json:"triggers"`
	NotificationGroupId  string    `json:"notificationGroupId"`
	NotificationGroupId2 string    `json:"_notificationGroupId"`

	//ParentId            string             `json:"_parentId"`
	//Deleted             bool               `json:"deleted"`
	//DeletedAt           string             `json:"deletedAt"`
	//DeletedBy           string             `json:"deletedBy"`
	//NotificationGroup         NotificationGroup  `json:"notificationGroup"`
	//Data                      struct{} `json:"data"`
	//WorkflowIntegrationStatus struct{} `json:"workflowIntegrationStatus"`
}

type WorkFlow struct {
	Data Data `json:"data"`
}
