package storage

import (
	"strings"

	"github.com/juju/errors"
	"github.com/pingcap/schrodinger/pkg/types"
)

/* ---------------- mysql storage ------------------*/

func (m *mysqlClient) setGithubTriggerInfo(info *types.GithubTriggerInfo) error {
	if _, err := m.db.NamedExec(triggerSet, githubTriggerInfoToParams(info)); err != nil {
		return errors.Trace(err)
	}
	return nil
}

func (m *mysqlClient) listGithubTriggerInfo() ([]*types.GithubTriggerInfo, error) {
	var infos []*types.GithubTriggerInfo
	rows, err := m.db.Queryx(triggerSelect, types.JobGitWebhook)
	if err != nil {
		return nil, errors.Trace(err)
	}
	for rows.Next() {
		var triggerJob triggerJob

		if err := rows.StructScan(&triggerJob); err != nil {
			return nil, errors.Trace(err)
		}

		infos = append(infos, &types.GithubTriggerInfo{
			JobID: triggerJob.Box,
			Repo:  *triggerJob.Repo,
			Hash:  *triggerJob.Hash,
		})
	}

	return infos, nil
}

func (m *mysqlClient) findGithubTriggerInfoByJobID(jobID int64) (*types.GithubTriggerInfo, error) {
	var triggerJob triggerJob

	if err := m.db.Get(&triggerJob, triggerSelectByJobID, types.JobGitWebhook, jobID); err != nil {
		if strings.Contains(err.Error(), "no rows in result set") {
			return nil, errors.NotFoundf("github trigger info %d", jobID)
		}
		return nil, errors.Trace(err)
	}
	return &types.GithubTriggerInfo{
		JobID: triggerJob.Box,
		Repo:  *triggerJob.Repo,
		Hash:  *triggerJob.Hash,
	}, nil
}

func (m *mysqlClient) setImmediatelyTriggerInfo(info *types.ImmediateTriggerInfo) error {
	if _, err := m.db.NamedExec(triggerSet, immediateTriggerInfoToParams(info)); err != nil {
		return errors.Trace(err)
	}
	return nil
}

func (m *mysqlClient) listImmediatelyTriggerInfo() ([]*types.ImmediateTriggerInfo, error) {
	var infos []*types.ImmediateTriggerInfo
	rows, err := m.db.Queryx(triggerSelect, types.JobImmediately)
	if err != nil {
		return nil, errors.Trace(err)
	}
	for rows.Next() {
		var triggerJob triggerJob

		if err := rows.StructScan(&triggerJob); err != nil {
			return nil, errors.Trace(err)
		}

		infos = append(infos, &types.ImmediateTriggerInfo{
			JobID:    triggerJob.Box,
			Triggerd: *triggerJob.Triggerd,
		})
	}

	return infos, nil
}

func (m *mysqlClient) findImmediatelyTriggerInfoByJobID(jobID int64) (*types.ImmediateTriggerInfo, error) {
	var triggerJob triggerJob

	if err := m.db.Get(&triggerJob, triggerSelectByJobID, types.JobImmediately, jobID); err != nil {
		if strings.Contains(err.Error(), "no rows in result set") {
			return nil, errors.NotFoundf("immediately trigger info %d", jobID)
		}
		return nil, errors.Trace(err)
	}
	return &types.ImmediateTriggerInfo{
		JobID:    triggerJob.Box,
		Triggerd: *triggerJob.Triggerd,
	}, nil
}

func githubTriggerInfoToParams(info *types.GithubTriggerInfo) map[string]interface{} {
	return map[string]interface{}{
		"type":     types.JobGitWebhook,
		"git_repo": info.Repo,
		"git_hash": info.Hash,
		"box":      info.JobID,
		"triggerd": nil,
		"value":    nil,
	}
}

func immediateTriggerInfoToParams(info *types.ImmediateTriggerInfo) map[string]interface{} {
	return map[string]interface{}{
		"type":     types.JobImmediately,
		"triggerd": info.Triggerd,
		"box":      info.JobID,
		"git_repo": nil,
		"git_hash": nil,
		"value":    nil,
	}
}

const triggerSet = `
REPLACE INTO trigger_job (
 type
,git_repo
,git_hash
,triggerd
,box
,value
) VALUES (
 :type
,:git_repo
,:git_hash
,:triggerd
,:box
,:value
) 
`

const triggerSelect = `
SELECT
 id
,type
,git_repo
,git_hash
,triggerd
,box
,value
FROM trigger_job
WHERE type = ?
`

const triggerSelectByJobID = `
SELECT
 id
,type
,git_repo
,git_hash
,triggerd
,box
,value
FROM trigger_job
WHERE type = ? AND box = ?
`

type triggerJob struct {
	ID       int64   `json:"id"`
	Type     string  `json:"type"`
	Repo     *string `json:"git_repo"`
	Hash     *string `json:"git_hash"`
	Triggerd *bool   `json:"triggerd"`
	Box      int64   `json:"box"`
	Value    *string `json:"value"`
}
