package dev_services

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

	"go.uber.org/zap"
)

func NewMDSampleStationServices(uStore db.AppStore) *MDSampleStationServices {
	return &MDSampleStationServices{
		MDSampleStationStore: uStore,
	}
}

type MDSampleStationServices struct {
	MDSampleStationStore db.AppStore
}

func (ss *MDSampleStationServices) GetMDSampleStationBreadcrumb() (models.BreadCrumbV1, error) {
	var ret models.BreadCrumbV1

	Breadcrumb := models.BreadCrumbV1{
		Title: "Master Sample Station",
		Item: []models.ItemBreadCrumbV1{
			{
				Item: "Dashboard",
				Url:  "/dev/dashboard",
			},
			{
				Item: "Master",
				Url:  "/dev/master",
			},
			{
				Item: "Sample Stasion",
				Url:  "",
			},
		},
	}

	ret = Breadcrumb
	return ret, nil
}

func (ss *MDSampleStationServices) GetListSampleStation(search string, currentPage int, rowPerPage int) ([]models.MDSampleStation, int, error) {
	var sampleStationList []models.MDSampleStation
	var totalData int

	offset := (currentPage - 1) * rowPerPage
	prm := "%" + strings.TrimSpace(search) + "%"
	querytotal := `
	SELECT COUNT(*)
	FROM t_samplestation 
	WHERE T_SampleStationIsActive = 'Y' AND (T_SampleStationCode LIKE ? OR T_SampleStationName LIKE ?)
	`
	if err := dbx.Handlex.Get(&totalData, querytotal, prm, prm); err != nil {
		return nil, 0, fmt.Errorf("error query get total data: %v", err)
	}

	query := `
	SELECT
	T_SampleStationID,
	T_SampleStationCode,
	T_SampleStationName,
	T_SampleStationNat_GroupID,
	T_SampleStationIsNonLab,
	T_SampleStationIsActive
	FROM t_samplestation
	WHERE T_SampleStationIsActive = 'Y'
	AND (T_SampleStationCode LIKE ? OR T_SampleStationName LIKE ?)
	ORDER BY T_SampleStationID ASC
	LIMIT ? OFFSET ?
	`
	if err := dbx.Handlex.Select(&sampleStationList, query, prm, prm, rowPerPage, offset); err != nil {
		return nil, 0, fmt.Errorf("error query database: %v", err)
	}

	for i := range sampleStationList {
		if len(sampleStationList[i].T_SampleStationIsNonLab) == 0 {
			sampleStationList[i].T_SampleStationIsNonLab = "LAB"
		}
	}

	totalPage := int(math.Ceil(float64(totalData) / float64(rowPerPage)))

	return sampleStationList, totalPage, nil
}

func (ss *MDSampleStationServices) GetMDSampleStationByID(id string) (models.MDSampleStation, error) {
	logger, _ := zap.NewProduction()

	var ret models.MDSampleStation
	q := `
		SELECT
		T_SampleStationID,
		T_SampleStationCode,
		T_SampleStationName,
		T_SampleStationNat_GroupID,
		T_SampleStationIsNonLab,
		T_SampleStationIsActive		
		FROM t_samplestation 
		WHERE T_SampleStationID = ?`

	err := dbx.Handlex.Get(&ret, q, id)
	if err != nil {
		defer logger.Sync()
		logger.Error("Error get data by ID", zap.String("ID", id), zap.Error(err))
		return ret, fmt.Errorf("query get data by id failed")
	}

	if len(ret.T_SampleStationIsNonLab) == 0 {
		ret.T_SampleStationIsNonLab = "LAB"
	}

	return ret, nil
}

func (ss *MDSampleStationServices) GetListGroupSampleStation() ([]models.MDSampleStationGroup, error) {
	data := []models.MDSampleStationGroup{
		{
			ID:    1,
			Group: "RADIODIAGNOSTIC",
		},
		{
			ID:    2,
			Group: "ELEKTROMEDIS",
		},
		{
			ID:    3,
			Group: "LAB",
		},
		{
			ID:    4,
			Group: "OTHERS",
		},
	}
	return data, nil
}

func (ss *MDSampleStationServices) AddMDSampleStation(code string, name string, group string) (models.MDSampleStation, error) {
	logger, _ := zap.NewProduction()
	var data models.MDSampleStation

	if strings.ToUpper(group) == "LAB" {
		group = " "
	}

	// cek existing code & name
	var count int
	var prmCode = "%" + code + "%"
	var prmName = "%" + name + "%"
	q := `
		SELECT COUNT(*)
		FROM t_samplestation
		WHERE (T_SampleStationCode LIKE ? OR T_SampleStationName LIKE ?) 
		AND T_SampleStationIsActive = 'Y'
	`
	err := dbx.Handlex.Get(&count, q, prmCode, prmName)
	if err != nil {
		defer logger.Sync()
		logger.Error("cek duplicate", zap.Any("code", prmCode), zap.Any("name", prmName))
		return data, fmt.Errorf("query failed to cek duplicate")
	}
	if count > 0 {
		defer logger.Sync()
		logger.Error("duplicate data", zap.Any("code", code), zap.Any("name", name))
		return data, fmt.Errorf("duplicate code or name")
	}

	q = `
		INSERT INTO t_samplestation (
			T_SampleStationCode,
			T_SampleStationName,
			T_SampleStationIsNonLab,
			T_SampleStationCreated,
			T_SampleStationCreatedUserID
		) VALUES (?,?,?,NOW(),1);
	`
	rst := dbx.Handlex.MustExec(q, code, name, group)
	insertedID, err := rst.LastInsertId()
	if err != nil {
		defer logger.Sync()
		logger.Error("error insert data", zap.Any("code", code), zap.Any("name", name), zap.Any("group", group))
		return data, fmt.Errorf("query failed insert data")
	}

	s := strconv.Itoa(int(insertedID))

	return ss.GetMDSampleStationByID(s)
}

func (ss *MDSampleStationServices) EditMDSampleStation(id string, code string, name string, group string) (models.MDSampleStation, error) {
	logger, _ := zap.NewProduction()
	var ret models.MDSampleStation

	if strings.ToUpper(group) == "LAB" {
		group = " "
	}

	// cek existeing code & name
	var count int
	var prmCode = "%" + code + "%"
	var prmName = "%" + name + "%"
	q := `
		SELECT COUNT(*)
		FROM t_samplestation
		WHERE (T_SampleStationCode LIKE ? OR T_SampleStationName LIKE ?) 
		AND T_SampleStationIsActive = 'Y'
		AND T_SampleStationID <> ?
	`
	err := dbx.Handlex.Get(&count, q, prmCode, prmName, id)
	if err != nil {
		defer logger.Sync()
		logger.Error("cek duplicate", zap.Any("code", code), zap.Any("name", name))
		return ret, fmt.Errorf("query failed to cek duplicate")
	}
	if count > 0 {
		defer logger.Sync()
		logger.Error("duplicate data", zap.Any("code", code), zap.Any("name", name))
		return ret, fmt.Errorf("duplicate code or name")
	}

	// update data
	q = `
		UPDATE t_samplestation SET 
			T_SampleStationCode = ?,
			T_SampleStationName = ?,
			T_SampleStationIsNonLab = ?,
			T_SampleStationLastUpdated = NOW(),
			T_SampleStationLastUpdatedUserID = 1
		WHERE T_SampleStationID = ?;
	`
	updt := dbx.Handlex.MustExec(q, code, name, group, id)
	_, err = updt.RowsAffected()
	if err != nil {
		defer logger.Sync()
		logger.Error("error update data", zap.Any("code", code), zap.Any("name", name), zap.Any("group", group))
		return ret, fmt.Errorf("query failed to update data")
	}

	return ss.GetMDSampleStationByID(id)
}

func (ss *MDSampleStationServices) DeleteMDSampleStation(id string) (models.MDSampleStation, error) {
	logger, _ := zap.NewProduction()
	var ret models.MDSampleStation

	q := `
	UPDATE t_samplestation
	SET 
	T_SampleStationIsActive = 'N',
	T_SampleStationDeleted = NOW(),
	T_SampleStationDeletedUserID = '1'
	WHERE T_SampleStationID = ?;
	`
	dlt := dbx.Handlex.MustExec(q, id)
	_, err := dlt.RowsAffected()
	if err != nil {
		defer logger.Sync()
		logger.Error("Error delete sample station", zap.String("id", id))
		return ret, fmt.Errorf("query failed")
	}

	ret, err = ss.GetMDSampleStationByID(id)
	if err != nil {
		defer logger.Sync()
		logger.Error("Error get sample station id", zap.String("id", id))
		return ret, fmt.Errorf("query failed")
	}

	return ret, nil
}
