package service

import (
	"fmt"
	"github.com/linmadan/egglib-go/core/application"
	"github.com/linmadan/egglib-go/utils/tool_funs"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/factory"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/log/command"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/log/dto"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/application/log/query"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/domain"
	"gitlab.fjmaimaimai.com/allied-creation/character-library-metadata-bastion/pkg/infrastructure/utils"
)

type LogService struct {
}

func (logService *LogService) CreateLog(createLogCommand *command.CreateLogCommand) (interface{}, error) {
	if err := createLogCommand.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	newLog := &domain.Log{
		ObjectName:    createLogCommand.ObjectName,
		ObjectType:    createLogCommand.ObjectType,
		OperationType: createLogCommand.OperationType,
		Content:       createLogCommand.Content,
		OperatorName:  createLogCommand.OperatorName,
	}
	var logRepository domain.LogRepository
	if value, err := factory.CreateLogRepository(map[string]interface{}{
		"transactionContext": transactionContext,
	}); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	} else {
		logRepository = value
	}
	if log, err := logRepository.Save(newLog); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	} else {
		if err := transactionContext.CommitTransaction(); err != nil {
			return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
		}
		return log, nil
	}
}

func (logService *LogService) GetLog(getLogQuery *query.GetLogQuery) (interface{}, error) {
	if err := getLogQuery.ValidateQuery(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	var logRepository domain.LogRepository
	if value, err := factory.CreateLogRepository(map[string]interface{}{
		"transactionContext": transactionContext,
	}); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	} else {
		logRepository = value
	}
	log, err := logRepository.FindOne(map[string]interface{}{"logId": getLogQuery.LogId})
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	if log == nil {
		return nil, application.ThrowError(application.RES_NO_FIND_ERROR, fmt.Sprintf("%s", string(getLogQuery.LogId)))
	} else {
		if err := transactionContext.CommitTransaction(); err != nil {
			return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
		}
		return log, nil
	}
}

func (logService *LogService) ListLog(listLogQuery *query.ListLogQuery) (interface{}, error) {
	if err := listLogQuery.ValidateQuery(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	var logRepository domain.LogRepository
	if value, err := factory.CreateLogRepository(map[string]interface{}{
		"transactionContext": transactionContext,
	}); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	} else {
		logRepository = value
	}
	if count, logs, err := logRepository.Find(tool_funs.SimpleStructToMap(listLogQuery)); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	} else {
		if err := transactionContext.CommitTransaction(); err != nil {
			return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
		}
		return map[string]interface{}{
			"count": count,
			"logs":  logs,
		}, nil
	}
}

func (logService *LogService) RemoveLog(removeLogCommand *command.RemoveLogCommand) (interface{}, error) {
	if err := removeLogCommand.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	var logRepository domain.LogRepository
	if value, err := factory.CreateLogRepository(map[string]interface{}{
		"transactionContext": transactionContext,
	}); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	} else {
		logRepository = value
	}
	log, err := logRepository.FindOne(map[string]interface{}{"logId": removeLogCommand.LogId})
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	if log == nil {
		return nil, application.ThrowError(application.RES_NO_FIND_ERROR, fmt.Sprintf("%s", string(removeLogCommand.LogId)))
	}
	if log, err := logRepository.Remove(log); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	} else {
		if err := transactionContext.CommitTransaction(); err != nil {
			return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
		}
		return log, nil
	}
}

func (logService *LogService) SearchLog(searchLogCommand *command.SearchLogCommand) (int64, interface{}, error) {
	if err := searchLogCommand.ValidateCommand(); err != nil {
		return 0, nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return 0, nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return 0, nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	logRepository, _, _ := factory.FastPgLog(transactionContext, 0)
	count, logs, err := logRepository.Find(utils.ObjectToMap(searchLogCommand))
	if err != nil {
		return 0, nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}

	var result = make([]*dto.LogDto, 0)
	for _, m := range logs {
		var item = &dto.LogDto{}
		item.Load(m)
		result = append(result, item)
	}

	if err := transactionContext.CommitTransaction(); err != nil {
		return 0, nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	return count, result, nil
}

func (logService *LogService) VerifiedStepLog(searchLogCommand *command.SearchLogCommand) (int64, interface{}, error) {
	if err := searchLogCommand.ValidateCommand(); err != nil {
		return 0, nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return 0, nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return 0, nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	_, sourceFile, err := factory.FastPgFile(transactionContext, searchLogCommand.SourceId)
	if err != nil {
		return 0, nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}

	searchLogCommand.LogType = domain.VerifiedStepLog.ToString()
	searchLogCommand.SourceId = 0
	searchLogCommand.InSourceId = []int{sourceFile.FileId, sourceFile.SourceFileId}
	searchLogCommand.PageNumber = 1
	searchLogCommand.PageSize = 1000

	logRepository, _, _ := factory.FastPgLog(transactionContext, 0)
	count, logs, err := logRepository.Find(utils.ObjectToMap(searchLogCommand))
	if err != nil {
		return 0, nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}

	var result = make([]*dto.VerifiedStepLogDto, 0)
	for _, m := range logs {
		var item = &dto.VerifiedStepLogDto{}
		item.Load(m)
		result = append(result, item)
	}

	if err := transactionContext.CommitTransaction(); err != nil {
		return 0, nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	return count, map[string]interface{}{
		"logs": result,
	}, nil
}

func (logService *LogService) UpdateLog(updateLogCommand *command.UpdateLogCommand) (interface{}, error) {
	if err := updateLogCommand.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()
	var logRepository domain.LogRepository
	if value, err := factory.CreateLogRepository(map[string]interface{}{
		"transactionContext": transactionContext,
	}); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	} else {
		logRepository = value
	}
	log, err := logRepository.FindOne(map[string]interface{}{"logId": updateLogCommand.LogId})
	if err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	}
	if log == nil {
		return nil, application.ThrowError(application.RES_NO_FIND_ERROR, fmt.Sprintf("%s", string(updateLogCommand.LogId)))
	}
	if err := log.Update(tool_funs.SimpleStructToMap(updateLogCommand)); err != nil {
		return nil, application.ThrowError(application.BUSINESS_ERROR, err.Error())
	}
	if log, err := logRepository.Save(log); err != nil {
		return nil, application.ThrowError(application.INTERNAL_SERVER_ERROR, err.Error())
	} else {
		if err := transactionContext.CommitTransaction(); err != nil {
			return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
		}
		return log, nil
	}
}

func NewLogService(options map[string]interface{}) *LogService {
	newLogService := &LogService{}
	return newLogService
}