package expense

import (
	"encoding/csv"
	"net/http"
	"time"

	"gitea.frenchtouch.duckdns.org/kratisto/budget-backend/handler"
	"gitea.frenchtouch.duckdns.org/kratisto/budget-backend/internal/account"
	"gitea.frenchtouch.duckdns.org/kratisto/budget-backend/internal/storage/dao/postgresql"
	"gitea.frenchtouch.duckdns.org/kratisto/budget-backend/internal/storage/model"
	"gitea.frenchtouch.duckdns.org/kratisto/budget-backend/internal/storage/validators"
	"gitea.frenchtouch.duckdns.org/kratisto/budget-backend/internal/utils"

	"github.com/gin-gonic/gin"
)

type Context struct {
	service        *Service
	db             *Database
	accountService *account.Service
	*handler.Context
}

func (c *Context) ImportExpenseFromCSV(gc *gin.Context) {
}
func (c *Context) CreateAnExpense(gc *gin.Context) {
	accountID := gc.Param("accountId")
	userId := gc.Param("userId")
	csvHeaderFile, err := gc.FormFile("attachment")
	if err != nil {
		utils.GetLogger().Info(err)
		utils.JSONErrorWithMessage(gc.Writer, model.ErrInternalServer, err.Error())
		return
	}
	if err == nil {
		csvFile, err := csvHeaderFile.Open()
		if err != nil {
			utils.GetLogger().Info(err)
			utils.JSONErrorWithMessage(gc.Writer, model.ErrInternalServer, err.Error())
			return
		}
		csvr := csv.NewReader(csvFile)
		csvr.FieldsPerRecord = -1
		csvr.Comma = ';'
		filedata, _ := csvr.ReadAll()

		account, err := c.accountService.GetASpecificAccountForUser(userId, accountID)
		if err != nil {
			utils.GetLogger().Info(err)
			utils.JSONErrorWithMessage(gc.Writer, model.ErrInternalServer, err.Error())
			return
		}
		err = c.service.ProcessCSVFile(filedata, account)
		if err != nil {
			utils.JSONErrorWithMessage(gc.Writer, model.ErrInternalServer, err.Error())
			return
		}
		return
	}
	var expense Expense
	var expenseEditable ExpenseEditable
	if err := gc.BindJSON(&expenseEditable); err != nil {
		utils.JSONError(gc.Writer, validators.NewDataValidationAPIError(err))
		return
	}
	expense = Expense{ExpenseEditable: expenseEditable, AccountId: accountID}
	err = c.service.CreateExpense(&expense)
	if err != nil {
		utils.GetLogger().Info(err)
		utils.JSONErrorWithMessage(gc.Writer, model.ErrInternalServer, err.Error())
		return
	}
	utils.JSON(gc.Writer, http.StatusCreated, expense)
}

func (c *Context) DeleteExpense(gc *gin.Context) {

}

func (c *Context) GetAllExpenses(gc *gin.Context) {
	accountId := gc.Param("accountId")
	from := gc.Query("from")
	to := gc.Query("to")
	var expenses []*Expense
	var err error
	if from != "" || to != "" {
		if to == "" {
			fromParsed, err := time.Parse("2006-01-02", from)
			if err == nil {
				to = time.Now().Format("2006-01-02")
			} else {
				to = fromParsed.AddDate(0, 1, 0).Format("2006-01-02")
			}
		}
		if from == "" {
			toParsed, err := time.Parse("2006-01-02", to)
			if err == nil {
				from = "1900-01-01"
			} else {
				from = toParsed.AddDate(0, -1, 0).Format("2006-01-02")
			}
		}
		expenses, err = c.service.GetExpensesOfAnAccountBetween(accountId, from, to)
	} else {
		expenses, err = c.service.GetAllExpensesOfAnAccount(accountId)
	}
	if e, ok := err.(*model.APIError); ok {
		utils.GetLoggerFromCtx(gc).WithError(err).WithField("type", e.Type).Error("error GetAllExpenses: get expenses")
		utils.JSONErrorWithMessage(gc.Writer, *e, e.Description)
	} else if err != nil {
		utils.GetLoggerFromCtx(gc).WithError(err).Error("error while get expenses")
		utils.JSONError(gc.Writer, model.ErrInternalServer)
		return
	}

	if len(expenses) == 0 {
		utils.JSON(gc.Writer, http.StatusNoContent, nil)
	} else {
		utils.JSON(gc.Writer, http.StatusOK, expenses)
	}
}

func (c *Context) GetAnExpenses(context *gin.Context) {

}

func NewHandler(ctx *handler.Context, db *postgresql.DatabasePostgreSQL) *Context {
	database := NewDatabase(db)
	service := NewService(database)
	accountService := account.NewService(account.NewDatabase(db))
	return &Context{service: service, db: database, accountService: accountService, Context: ctx}
}
