// Package repository add by blacknc <blacknc@163.com> at 2023/03/17 18:13:56
package repository

import (
	"context"
	"dataservices/commons/errs"
	"dataservices/commons/utils"
	"dataservices/internal/entity"
	"time"

	"gorm.io/gorm"
)

func ListDataAppDeploymentSettingsByGithubRepo(ctx context.Context, repoId int64, branch string, dir string) ([]*entity.DataAppDeploymentSetting, error) {
	var res []*entity.DataAppDeploymentSetting
	txDB := MustFromContext(ctx).Table(entity.TableDataAppDeploymentSettings).Where("github_repository_id=? and github_branch=? and github_directory=?", repoId, branch, dir)
	err := txDB.Find(&res).Error
	if err != nil {
		return nil, errs.WrapGORMError(err, "Failed to list deploymentsettings by repoId: %d , branch: %s , dir: %s", repoId, branch, dir)
	}
	return res, nil
}

func ListDataAppDeploymentSettingsByBranch(ctx context.Context, repoId int64, branch string) ([]*entity.DataAppDeploymentSetting, error) {
	var res []*entity.DataAppDeploymentSetting
	txDB := MustFromContext(ctx).Table(entity.TableDataAppDeploymentSettings).Where("github_repository_id=? and github_branch=?", repoId, branch)
	err := txDB.Find(&res).Error
	if err != nil {
		return nil, errs.WrapGORMError(err, "Failed to list deploymentsettings by repoId: %d , branch: %s", repoId, branch)
	}
	return res, nil
}

func ListDataAppDeploymentSettingsByInstallationId(ctx context.Context, githubInstallationId int64) ([]*entity.DataAppDeploymentSetting, error) {
	var res []*entity.DataAppDeploymentSetting
	txDB := MustFromContext(ctx).Table(entity.TableDataAppDeploymentSettings).Where("github_installation_id=?", githubInstallationId)
	err := txDB.Find(&res).Error
	if err != nil {
		return nil, err
	}
	return res, nil
}

func ListDataAppDeploymentSettingsByRepoId(ctx context.Context, repoId int64) ([]*entity.DataAppDeploymentSetting, error) {
	var res []*entity.DataAppDeploymentSetting
	txDB := MustFromContext(ctx).Table(entity.TableDataAppDeploymentSettings).Where("github_repository_id=?", repoId)
	err := txDB.Find(&res).Error
	if err != nil {
		return nil, errs.WrapGORMError(err, "Failed to list deploymentsettings by repoId: %d", repoId)
	}
	return res, nil
}

func ClearDataAppDeploymentSettingsGithubLikage(ctx context.Context, primaryId uint64) error {
	return MustFromContext(ctx).Table(
		entity.TableDataAppDeploymentSettings,
	).Where(
		"id=?",
		primaryId,
	).Updates(
		map[string]interface{}{
			"enable_automatic_deployment": false,
			"github_installation_id":      0,
			"github_repository_id":        0,
			"github_branch":               "",
			"github_directory":            "",
		},
	).Error
}

func ClearDataAppDeploymentSettingsGithubLikageByDataappId(ctx context.Context, dataappId uint64) error {
	return MustFromContext(ctx).Table(
		entity.TableDataAppDeploymentSettings,
	).Where(
		"dataapp_id=?",
		dataappId,
	).Updates(
		map[string]interface{}{
			"enable_automatic_deployment": false,
			"github_installation_id":      0,
			"github_repository_id":        0,
			"github_branch":               "",
			"github_directory":            "",
		},
	).Error
}

func UpdateDataAppDeploymentLogStatus(ctx context.Context, logId uint64, status entity.DataAppDeploymentLogStatus) error {
	log, err := GetDataAppDeploymentLog(ctx, logId)
	if err != nil {
		return err
	}
	log.Status = status
	log.UpdatedAt = utils.Now()
	if status == entity.DataAppDeploymentStatusSuccess || status == entity.DataAppDeploymentStatusFailed {
		log.FinishedAt = utils.Now()
	} else if status == entity.DataAppDeploymentStatusRunning {
		log.RanAt = utils.Now()
	}
	err = UpdateDataAppDeployLog(ctx, log)
	if err != nil {
		return err
	}
	return nil
}

func ListDataAppDeploymentLogs(ctx context.Context, appId uint64, limit int) ([]*entity.DataAppDeploymentLog, error) {
	var res []*entity.DataAppDeploymentLog
	txDB := MustFromContext(ctx).Table(entity.TableDataAppDeploymentLogs).Where("dataapp_id=?", appId).Order("created_at DESC").Limit(limit)
	err := txDB.Find(&res).Error
	if err != nil {
		return nil, errs.WrapGORMError(err, "Failed to list deploymentlogs by app_id: %d", appId)
	}
	return res, nil

}

func ListDataAppDeploymentLogsWithPager(ctx context.Context, appId uint64, preID uint64, pageSize int) ([]*entity.DataAppDeploymentLog, error) {
	var res []*entity.DataAppDeploymentLog
	txDB := MustFromContext(ctx).Table(entity.TableDataAppDeploymentLogs).Where("dataapp_id=? AND id < ?", appId, preID).Order("id DESC").Limit(pageSize)
	err := txDB.Find(&res).Error
	if err != nil {
		return nil, errs.WrapGORMError(err, "Failed to list deploymentlogs page by app_id: %d", appId)
	}
	return res, nil
}

func GetDataAppDeploymentLogCount(ctx context.Context, appId uint64) (int64, error) {
	var count int64
	err := MustFromContext(ctx).Table(entity.TableDataAppDeploymentLogs).Where("dataapp_id=?", appId).Where("status=?", entity.DataAppDeploymentStatusSuccess).Count(&count).Error
	if err != nil {
		return 0, errs.WrapGORMError(err, "Failed to get deployment count")
	}
	return count, nil
}

func GetLatestSuccDataAppDeploymentLog(ctx context.Context, appId uint64, before string) (*entity.DataAppDeploymentLog, error) {
	res := entity.DataAppDeploymentLog{}
	tx := MustFromContext(ctx).Table(entity.TableDataAppDeploymentLogs).Where("dataapp_id=?", appId).Where("status=?", entity.DataAppDeploymentStatusSuccess).Order("created_at DESC")
	if before != "" {
		tx.Where("created_at < ?", before)
	}
	err := tx.First(&res).Error
	if err != nil {
		return nil, errs.WrapGORMError(err, "Failed to get deploylog: %d", appId)
	}
	return &res, nil
}

func GetDataAppDeploymentLog(ctx context.Context, logId uint64) (*entity.DataAppDeploymentLog, error) {
	res := entity.DataAppDeploymentLog{}
	err := MustFromContext(ctx).Table(entity.TableDataAppDeploymentLogs).Where("id=?", logId).First(&res).Error
	if err != nil {
		return nil, errs.WrapGORMError(err, "Failed to get deploylog: %d", logId)
	}
	return &res, nil
}

func UpdateDataAppDeployLogName(ctx context.Context, deploymentID uint64, deploymentName string) error {
	if err := MustFromContext(ctx).Table(entity.TableDataAppDeploymentLogs).Where("id=?", deploymentID).Update("name", deploymentName).Error; err != nil {
		return errs.WrapGORMError(err, "Failed to update dataapp deployment name: %d", deploymentID)
	}
	return nil
}

func UpdateDataAppDeployLog(ctx context.Context, log *entity.DataAppDeploymentLog) error {
	if err := MustFromContext(ctx).Table(entity.TableDataAppDeploymentLogs).Where("id=?", log.ID).Updates(&log).Error; err != nil {
		return errs.WrapGORMError(err, "Failed to update dataappdeploymentlog: %d", log.ID)
	}
	return nil
}

func GetLastDataAppFinishedDeploymentInTime(ctx context.Context, dataAppID uint64, tm time.Time) (*entity.DataAppDeploymentLog, error) {
	var res entity.DataAppDeploymentLog
	txDB := MustFromContext(ctx).Table(entity.TableDataAppDeploymentLogs).
		Where("dataapp_id", dataAppID).
		Where("status in (?, ?) AND finished_at > ?", entity.DataAppDeploymentStatusSuccess, entity.DataAppDeploymentStatusFailed, tm.Format("2006-01-02 15:04:05")).
		Order("created_at DESC")
	err := txDB.First(&res).Error
	if err != nil {
		return nil, errs.WrapGORMError(err, "Failed to list finished deploymentlogs")
	}
	return &res, nil
}

func ListDataAppUnfinishedDeployment(ctx context.Context, dataAppID uint64) ([]*entity.DataAppDeploymentLog, error) {
	var res []*entity.DataAppDeploymentLog
	txDB := MustFromContext(ctx).Table(entity.TableDataAppDeploymentLogs).
		Where("dataapp_id=?", dataAppID).
		Where("status=? OR status=?", entity.DataAppDeploymentStatusPending, entity.DataAppDeploymentStatusRunning)
	err := txDB.Find(&res).Error
	if err != nil {
		return nil, errs.WrapGORMError(err, "Failed to list waiting deploymentlogs")
	}
	return res, nil
}

func ListWaitingDeploymentLogs(ctx context.Context) ([]*entity.DataAppDeploymentLog, error) {
	var res []*entity.DataAppDeploymentLog
	txDB := MustFromContext(ctx).Table(entity.TableDataAppDeploymentLogs).
		Where("status=? OR (status=? AND ran_at<?)",
			entity.DataAppDeploymentStatusPending,
			entity.DataAppDeploymentStatusRunning,
			time.Now().Add(-time.Minute*2).Format("2006-01-02 15:04:05"))
	err := txDB.Find(&res).Error
	if err != nil {
		return nil, errs.WrapGORMError(err, "Failed to list waiting deploymentlogs")
	}
	return res, nil
}

func CreateDataAppDeploymentLog(ctx context.Context, deploymentLog *entity.DataAppDeploymentLog) (*entity.DataAppDeploymentLog, error) {
	if err := MustFromContext(ctx).Table(entity.TableDataAppDeploymentLogs).Create(deploymentLog).Error; err != nil {
		return nil, errs.WrapGORMError(err, "Failed to create dataapp deployment log")
	}
	return deploymentLog, nil
}

func SaveDataAppDeploymentSetting(ctx context.Context, deploymentSetting *entity.DataAppDeploymentSetting) (*entity.DataAppDeploymentSetting, error) {
	if err := MustFromContext(ctx).Table(entity.TableDataAppDeploymentSettings).Save(deploymentSetting).Error; err != nil {
		return nil, errs.WrapGORMError(err, "Failed to create dataapp deployment Setting")
	}
	return deploymentSetting, nil
}

func GetDataAppDeploySetting(ctx context.Context, appId uint64) (*entity.DataAppDeploymentSetting, error) {
	res, err := GetDataAppDeploySettingRaw(ctx, appId)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			res.EnableUIDrafts = false
			res.EnableAutoDeploy = false
			res.DataappID = appId
			return res, nil
		}
		return nil, errs.WrapGORMError(err, "failed to get deployment setting")
	}
	return res, nil
}

func GetDataAppDeploySettingRaw(ctx context.Context, appId uint64) (*entity.DataAppDeploymentSetting, error) {
	res := entity.DataAppDeploymentSetting{}
	err := MustFromContext(ctx).Table(entity.TableDataAppDeploymentSettings).Where("dataapp_id=?", appId).First(&res).Error
	if err != nil {
		return &res, err
	}
	return &res, nil
}
