package dev_services

import (
	"cpone/db"
	"cpone/models"
	dbx "cpone/package/database"
	"fmt"
	"math"
	"strconv"
	"strings"

	"go.uber.org/zap"
)

func NewMdNatUnitServices(uStore db.AppStore) *MdNatUnitServices {
	return &MdNatUnitServices{
		MdNatUnitStore: uStore,
	}
}

type MdNatUnitServices struct {
	MdNatUnitStore db.AppStore
}

func (nu *MdNatUnitServices) GetListMdNatUnit(search string, currentPage int, rowPerPage int) ([]models.NatUnit, int, error) {
	var natUnitList []models.NatUnit
	var totalData int
	offset := (currentPage - 1) * rowPerPage
	prm := "%" + strings.TrimSpace(search) + "%"
	querytotal := `SELECT COUNT(*)
			FROM nat_unit
			WHERE Nat_UnitIsActive = 'Y'
			AND (Nat_UnitCode LIKE ? OR Nat_UnitName LIKE ?)`

	if err := dbx.Handlex.Get(&totalData, querytotal, prm, prm); err != nil {
		return nil, 0, fmt.Errorf("error querying database: %v", err)
	}

	query := `SELECT ROW_NUMBER() OVER (ORDER BY Nat_UnitID DESC) AS nomor,
		Nat_UnitID,
		Nat_UnitCode,
		Nat_UnitName,
		Nat_UnitCreated,
		Nat_UnitLastUpdated,
		Nat_UnitIsActive
		FROM nat_unit
		WHERE Nat_UnitIsActive = 'Y'
		AND (Nat_UnitCode LIKE ? OR Nat_UnitName LIKE ?)
		ORDER BY Nat_UnitID DESC
		LIMIT ? OFFSET ?`

	if err := dbx.Handlex.Select(&natUnitList, query, prm, prm, rowPerPage, offset); err != nil {
		return nil, 0, fmt.Errorf("error querying database: %v", err)
	}
	totalPage := int(math.Ceil(float64(totalData) / float64(rowPerPage)))

	return natUnitList, totalPage, nil
}

func (nu *MdNatUnitServices) GetMdNatUnitBreadCrumb(title string) (models.BreadCrumbV1, error) {
	var ret models.BreadCrumbV1

	dummyBreadcrumb := []models.BreadCrumbV1{
		{
			Title: "Master Unit",
			Item: []models.ItemBreadCrumbV1{
				{
					Item: "Dashboard",
					Url:  "/dev/dashboard",
				},
				{
					Item: "Master",
					Url:  "/dev/master",
				},
				{
					Item: "Unit",
					Url:  "",
				},
			},
		},

		{
			Title: "Master User",
			Item: []models.ItemBreadCrumbV1{
				{
					Item: "Dashboard",
					Url:  "/dev/dashboard",
				},
				{
					Item: "Master",
					Url:  "/dev/master",
				},
				{
					Item: "User",
					Url:  "",
				},
			},
		},
	}

	for _, breadcrumb := range dummyBreadcrumb {
		if breadcrumb.Title == title {
			ret = breadcrumb
			return ret, nil
		}
	}

	return ret, nil
}

func (nu *MdNatUnitServices) GetMdNatUnitByID(id string) (models.NatUnit, error) {
	logger, _ := zap.NewProduction()

	var data models.NatUnit
	err := dbx.Handlex.Get(&data, `SELECT * FROM nat_unit
	WHERE Nat_UnitID = ?`, id)

	if err != nil {
		defer logger.Sync()
		logger.Error("Error get data unit by id",
			zap.String("ID", id),
			zap.Error(err),
		)
		return data, fmt.Errorf("QUERY_FAILED")
	}
	return data, nil
}

func (nu *MdNatUnitServices) AddMdNatUnit(code string, name string) (models.NatUnit, error) {
	logger, _ := zap.NewProduction()
	var data models.NatUnit
	var datacek []models.NatUnit

	qryCek := `SELECT Nat_UnitCode FROM nat_unit
		WHERE Nat_UnitCode = ? AND Nat_UnitIsActive = 'Y'`
	err := dbx.Handlex.Select(&datacek, qryCek, code)

	if err != nil {
		defer logger.Sync()
		logger.Error("Error cek data by code",
			zap.String("code", code),
			zap.Any("datacek", datacek),
		)
		return data, fmt.Errorf("QUERY_FAILED")
	}

	if len(datacek) > 0 {
		defer logger.Sync()
		logger.Error("Code already taken by another data",
			zap.String("code", code),
		)
		return data, fmt.Errorf("code sudah dipakai")
	}

	qry := `INSERT INTO nat_unit
		(Nat_UnitCode,
		Nat_UnitName) VALUES(?,?)`
	rst := dbx.Handlex.MustExec(qry, code, name)
	insertedID, err := rst.LastInsertId()
	if err != nil {
		defer logger.Sync()
		logger.Error("Error Insert natunit",
			zap.String("code", code),
			zap.String("name", name),
		)
		return data, fmt.Errorf("QUERY_FAILED")
	}

	s := strconv.Itoa(int(insertedID))
	data, err = nu.GetMdNatUnitByID(s)
	if err != nil {
		defer logger.Sync()
		logger.Error("Error get natunit by id",
			zap.String("code", code),
			zap.String("name", name),
		)
		return data, fmt.Errorf("QUERY_FAILED")
	}
	return data, nil
}

func (nu *MdNatUnitServices) EditMdNatUnit(id string, code string, name string) (models.NatUnit, error) {
	logger, _ := zap.NewProduction()
	var data models.NatUnit
	var datacek []models.NatUnit

	qryCek := `SELECT Nat_UnitCode FROM nat_unit
		WHERE Nat_UnitCode = ? AND Nat_UnitIsActive = 'Y' AND Nat_UnitID <> ?`
	err := dbx.Handlex.Select(&datacek, qryCek, code, id)

	if err != nil {
		defer logger.Sync()
		logger.Error("Error cek data by code",
			zap.String("code", code),
			zap.Any("datacek", datacek),
		)
		return data, fmt.Errorf("QUERY_FAILED")
	}

	if len(datacek) > 0 {
		defer logger.Sync()
		logger.Error("Code already taken by another data",
			zap.String("code", code),
		)
		return data, fmt.Errorf("code sudah dipakai")
	}

	qry := `UPDATE nat_unit
		SET Nat_UnitCode = ?,
		Nat_UnitName = ?,
		Nat_UnitLastUpdated = NOW()
		WHERE Nat_UnitID = ?`
	rst := dbx.Handlex.MustExec(qry, code, name, id)
	_, err = rst.RowsAffected()
	if err != nil {
		defer logger.Sync()
		logger.Error("Error Update natunit",
			zap.String("code", code),
			zap.String("name", name),
		)
		return data, fmt.Errorf("QUERY_FAILED")
	}

	data, err = nu.GetMdNatUnitByID(id)
	if err != nil {
		defer logger.Sync()
		logger.Error("Error get natunit by id",
			zap.String("code", code),
			zap.String("name", name),
		)
		return data, fmt.Errorf("QUERY_FAILED")
	}
	return data, nil
}

func (nu *MdNatUnitServices) DeleteMdNatUnit(id string) (models.NatUnit, error) {
	logger, _ := zap.NewProduction()
	var data models.NatUnit
	qry := `UPDATE nat_unit
		SET Nat_UnitLastUpdated = NOW(),
		Nat_UnitIsActive = 'N'
		WHERE Nat_UnitID = ?`
	rst := dbx.Handlex.MustExec(qry, id)
	_, err := rst.RowsAffected()
	if err != nil {
		defer logger.Sync()
		logger.Error("Error delete nat unit",
			zap.String("id", id),
		)
		return data, fmt.Errorf("QUERY_FAILED")
	}

	data, err = nu.GetMdNatUnitByID(id)
	if err != nil {
		defer logger.Sync()
		logger.Error("Error get nat unit by id",
			zap.String("id", id),
		)
		return data, fmt.Errorf("QUERY_FAILED")
	}
	return data, nil
}
