// Copyright 2019 Drone IO, Inc.
//
// 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.

package build

import (
	"database/sql"
	"encoding/json"

	"github.com/drone/drone/core"
	"github.com/drone/drone/store/shared/db"

	"github.com/jmoiron/sqlx/types"
)

// helper function converts the Build structure to a set
// of named query parameters.
func toParams(build *core.Build) map[string]interface{} {
	return map[string]interface{}{
		"build_id":            build.ID,
		"build_repo_id":       build.RepoID,
		"build_trigger":       build.Trigger,
		"build_number":        build.Number,
		"build_parent":        build.Parent,
		"build_status":        build.Status,
		"build_error":         build.Error,
		"build_event":         build.Event,
		"build_action":        build.Action,
		"build_link":          build.Link,
		"build_timestamp":     build.Timestamp,
		"build_title":         build.Title,
		"build_message":       build.Message,
		"build_before":        build.Before,
		"build_after":         build.After,
		"build_ref":           build.Ref,
		"build_source_repo":   build.Fork,
		"build_source":        build.Source,
		"build_target":        build.Target,
		"build_author":        build.Author,
		"build_author_name":   build.AuthorName,
		"build_author_email":  build.AuthorEmail,
		"build_author_avatar": build.AuthorAvatar,
		"build_sender":        build.Sender,
		"build_params":        encodeParams(build.Params),
		"build_cron":          build.Cron,
		"build_deploy":        build.Deploy,
		"build_deploy_id":     build.DeployID,
		"build_debug":         build.Debug,
		"build_started":       build.Started,
		"build_finished":      build.Finished,
		"build_created":       build.Created,
		"build_updated":       build.Updated,
		"build_version":       build.Version,
	}
}

// helper function converts the Stage structure to a set
// of named query parameters.
func toStageParams(stage *core.Stage) map[string]interface{} {
	return map[string]interface{}{
		"stage_id":         stage.ID,
		"stage_repo_id":    stage.RepoID,
		"stage_build_id":   stage.BuildID,
		"stage_number":     stage.Number,
		"stage_name":       stage.Name,
		"stage_kind":       stage.Kind,
		"stage_type":       stage.Type,
		"stage_status":     stage.Status,
		"stage_error":      stage.Error,
		"stage_errignore":  stage.ErrIgnore,
		"stage_exit_code":  stage.ExitCode,
		"stage_limit":      stage.Limit,
		"stage_limit_repo": stage.LimitRepo,
		"stage_os":         stage.OS,
		"stage_arch":       stage.Arch,
		"stage_variant":    stage.Variant,
		"stage_kernel":     stage.Kernel,
		"stage_machine":    stage.Machine,
		"stage_started":    stage.Started,
		"stage_stopped":    stage.Stopped,
		"stage_created":    stage.Created,
		"stage_updated":    stage.Updated,
		"stage_version":    stage.Version,
		"stage_on_success": stage.OnSuccess,
		"stage_on_failure": stage.OnFailure,
		"stage_depends_on": encodeSlice(stage.DependsOn),
		"stage_labels":     encodeParams(stage.Labels),
	}
}

func encodeParams(v map[string]string) types.JSONText {
	raw, _ := json.Marshal(v)
	return types.JSONText(raw)
}

func encodeSlice(v []string) types.JSONText {
	raw, _ := json.Marshal(v)
	return types.JSONText(raw)
}

// helper function scans the sql.Row and copies the column
// values to the destination object.
func scanRow(scanner db.Scanner, dest *core.Build) error {
	paramsJSON := types.JSONText{}
	err := scanner.Scan(
		&dest.ID,
		&dest.RepoID,
		&dest.Trigger,
		&dest.Number,
		&dest.Parent,
		&dest.Status,
		&dest.Error,
		&dest.Event,
		&dest.Action,
		&dest.Link,
		&dest.Timestamp,
		&dest.Title,
		&dest.Message,
		&dest.Before,
		&dest.After,
		&dest.Ref,
		&dest.Fork,
		&dest.Source,
		&dest.Target,
		&dest.Author,
		&dest.AuthorName,
		&dest.AuthorEmail,
		&dest.AuthorAvatar,
		&dest.Sender,
		&paramsJSON,
		&dest.Cron,
		&dest.Deploy,
		&dest.DeployID,
		&dest.Debug,
		&dest.Started,
		&dest.Finished,
		&dest.Created,
		&dest.Updated,
		&dest.Version,
	)
	dest.Params = map[string]string{}
	json.Unmarshal(paramsJSON, &dest.Params)
	return err
}

// helper function scans the sql.Row and copies the column
// values to the destination object.
func scanRows(rows *sql.Rows) ([]*core.Build, error) {
	defer rows.Close()

	builds := []*core.Build{}
	for rows.Next() {
		build := new(core.Build)
		err := scanRow(rows, build)
		if err != nil {
			return nil, err
		}
		builds = append(builds, build)
	}
	return builds, nil
}
