package transabsensi

import (
	"encoding/base64"
	"errors"
	"fmt"
	"log"
	"os"
	"strconv"
	"strings"
	"time"

	"com.sismedika.com.absensi/graph/model"
	"com.sismedika.com.absensi/pkg/config"
	db "com.sismedika.com.absensi/pkg/database"
)

// diambil dari graph/model/struct nya TransAbsensiResponse
type TransAbsensiCheckDistanceResponse model.TransAbsensiCheckDistanceResponse

type TransAbsensiResponse model.TransAbsensiResponse

type TransAbsensiCheckTimeAttendanceResponse model.TransAbsensiCheckTimeAttendanceResponse

type RekapKehadiranHomeScreen model.RekapKehadiranHomeScreen

// fungsi untuk Check Distance antara kantor dengan current user location
func (transabsensi *TransAbsensiCheckDistanceResponse) CheckDistance(M_StaffID string, M_CompanyID string, CurrentLatitude string, CurrentLongitude string) (*model.TransAbsensiCheckDistanceResponse, error) {
	// inisialisasi
	var err error
	var ret model.TransAbsensiCheckDistanceResponse
	var rMaxDistance int
	var rCurrentDistance float64
	var rMCompanyLongitude string
	var rMCompanyLatitude string
	var statusCheck string

	q := `SELECT
	M_CompanyLatitude,
	M_CompanyLongitude,
	M_CompanyMaxDistance
	FROM m_company
	WHERE M_CompanyIsActive = 'Y'
	AND M_CompanyID = ?`

	row := db.Handle.QueryRow(
		q,
		M_CompanyID)
	db.LogSQL(q)
	err = row.Scan(
		&rMCompanyLatitude,
		&rMCompanyLongitude,
		&rMaxDistance,
	)

	if err != nil {
		log.Printf("Error m_company select max distance: %v", err)
		log.Printf("Executing query: %s\n", q)
		return nil, err
	}

	// get distance
	qCurrentDistance := `SELECT distance_v2(?, ?, ?, ?)`

	rowxCurrentDistance := db.Handle.QueryRow(
		qCurrentDistance,
		CurrentLatitude,
		CurrentLongitude,
		rMCompanyLatitude,
		rMCompanyLongitude,
	)
	db.LogSQL(qCurrentDistance)
	err = rowxCurrentDistance.Scan(
		&rCurrentDistance,
	)

	if err != nil {
		log.Printf("Error m_staff select: %v", err)
		log.Printf("Executing query: %s\n", qCurrentDistance)
		return nil, err
	}

	// check distance
	qCheckDistance := `SELECT IF(distance_v2(?, ?, ?, ?) < ?, 'range', 'not range') AS distance_status`

	rowx := db.Handle.QueryRow(
		qCheckDistance,
		CurrentLatitude,
		CurrentLongitude,
		rMCompanyLatitude,
		rMCompanyLongitude,
		rMaxDistance,
	)
	db.LogSQL(qCheckDistance)
	err = rowx.Scan(
		&statusCheck,
	)

	if err != nil {
		log.Printf("Error m_staff select: %v", err)
		log.Printf("Executing query: %s\n", qCheckDistance)
		return nil, err
	}

	if statusCheck == "range" {
		// buat di set isi nya kosong dulu
		ret.Status = new(string)
		ret.Message = new(string)
		ret.Selfie = new(string)
		ret.CurrentDistance = new(string)
		ret.MaxDistance = new(string)
		ret.Unit = new(string)

		// di set kan langsung dengan * atau pointer
		*ret.Status = "OK"
		*ret.Selfie = "FALSE"
		*ret.Unit = "m"
		*ret.CurrentDistance = strconv.FormatFloat(rCurrentDistance, 'f', -1, 64)
		*ret.MaxDistance = strconv.Itoa(rMaxDistance)
		*ret.Message = "Masih dalam jarak absensi"
	}

	if statusCheck != "range" {
		// buat di set isi nya kosong dulu
		ret.Status = new(string)
		ret.Message = new(string)
		ret.Selfie = new(string)
		ret.CurrentDistance = new(string)
		ret.MaxDistance = new(string)
		ret.Unit = new(string)

		// di set kan langsung dengan * atau pointer
		*ret.Status = "OK"
		*ret.Selfie = "TRUE"
		*ret.Unit = "m"
		*ret.CurrentDistance = strconv.FormatFloat(rCurrentDistance, 'f', -1, 64)
		*ret.MaxDistance = strconv.Itoa(rMaxDistance)
		*ret.Message = "Max Distance : " + strconv.Itoa(rMaxDistance) + " meter. Current Distance: " + strconv.FormatFloat(rCurrentDistance, 'f', -1, 64) + ". Jauh dari area absensi, perlu foto selfie"
	}

	// hasil return nya
	return &ret, err
}

// fungsi untuk absen masuk clock in
func (transabsensi *TransAbsensiResponse) ClockInAbsensi(T_TransactionM_StaffID string, T_TransactionM_CompanyID string, T_TransactionCurrentLatitude string, T_TransactionCurrentLongitude string, T_TransactionCurrentDistance string, T_TransactionSelfiePhoto string, token string, isSelfie string) (*model.TransAbsensiResponse, error) {
	// inisialisasi
	var err error
	var ret model.TransAbsensiResponse
	var varGetToken string
	var varGetM_StaffNIP string
	var varProsesFotoSelfie string
	var jamClockIn string
	var varFileName string

	// check user token
	qCheckTokenStaff := `SELECT 
	M_StaffToken,
	LOWER(M_StaffNIP) AS M_StaffNIP
	FROM m_staff
	WHERE M_StaffIsActive = 'Y'
	AND M_StaffToken = ?
	`

	rowCheckTokenStaff := db.Handle.QueryRow(
		qCheckTokenStaff,
		token,
	)
	db.LogSQL(qCheckTokenStaff)
	err = rowCheckTokenStaff.Scan(
		&varGetToken,
		&varGetM_StaffNIP,
	)

	if err != nil {
		log.Printf("Error m_staff select token: %v", err)
		log.Printf("Executing query: %s\n", qCheckTokenStaff)
		return nil, err
	}

	// check varGetToken jk M_StaffToken kosong
	if varGetToken == "" {
		log.Printf("Error Token Kosong, Silahkan Login Dulu: %v", err)
		log.Printf("Executing query: %s\n", qCheckTokenStaff)
		return nil, err
	}

	ret.Status = new(string)
	ret.Message = new(string)

	// lanjut proses absen
	if varGetToken != "" {

		// tanpa selfie T_TransactionSelfiePhoto di set kosong
		if isSelfie != "TRUE" {
			T_TransactionSelfiePhoto = ""
			varProsesFotoSelfie = ""

			// setting jam absen
			currentTime := time.Now()
			jam := currentTime.Hour()
			menit := currentTime.Minute()
			detik := currentTime.Second()

			jamClockIn = fmt.Sprintf("%02d:%02d:%02d", jam, menit, detik)
		}

		// selfie true
		if isSelfie == "TRUE" {

			// pecah string
			strToArrayFoto := strings.Split(T_TransactionSelfiePhoto, ",")

			// check apakah sudah sesuai apa belum
			if len(strToArrayFoto) == 0 {
				log.Printf("Eror Tidak Sesuai Format %v", err)
				return &ret, err
			}

			// jika sesuai ambil strToArrayFoto ke 1 atau index ke 1
			if len(strToArrayFoto) > 0 {
				base64DataFoto := strToArrayFoto[1]
				T_TransactionSelfiePhoto = base64DataFoto
			}

			currentTime := time.Now()

			// setting jam absen
			jam := currentTime.Hour()
			menit := currentTime.Minute()
			detik := currentTime.Second()

			jamClockIn = fmt.Sprintf("%02d:%02d:%02d", jam, menit, detik)

			formattedTime := currentTime.Format("2006-01-02_15_04_05")
			// buat nama file
			varProsesFotoSelfie = "clockin_" + varGetM_StaffNIP + "_" + formattedTime
			strPhoto := varProsesFotoSelfie + ".jpg"

			// folder upload file nya selfie_attachment akan otomatis sesuai bulan dan tahun
			folderName := currentTime.Format("200601")
			folder := "selfie_attachment/" + folderName + "/"
			photoPath := config.Data.Get("document") + folder

			log.Printf("documentPath: %s", photoPath)

			// create folder selfie_attachment jika belum ada
			if _, err := os.Stat(photoPath); errors.Is(err, os.ErrNotExist) {
				err = os.MkdirAll(photoPath, os.ModePerm.Perm())
				if err != nil {
					log.Printf("here %v", err)
					return &ret, err
				}
			}

			photoPath = photoPath + strPhoto

			// proses decode
			decodedByte, err := base64.StdEncoding.DecodeString(T_TransactionSelfiePhoto)

			if err != nil {
				log.Printf("here %v", err)
				return &ret, err
			}

			fs, err := os.Create(photoPath)
			if err != nil {
				log.Printf("here %v", err)
				return &ret, err
			}
			defer fs.Close()
			fs.Write(decodedByte)
			fs.Sync()

			varProsesFotoSelfie = "selfie_attachment/" + folderName + "/" + strPhoto
			varFileName = strPhoto
		}

		qInsertClockIn := `INSERT INTO t_transaction (
			T_TransactionM_AbsensiTypeID,
			T_TransactionM_StaffID,
			T_TransactionM_CompanyID,
			T_TransactionClockAbsensi,
			T_TransactionDate,
			T_TransactionCurrentLatitude,
			T_TransactionCurrentLongitude,
			T_TransactionCurrentDistance,
			T_TransactionFileName,
			T_TransactionSelfiePhotoPath,
			T_TransactionIsActive,
			T_TransactionCreated
		) VALUES (
			?,
			?,
			?,
			?,
			NOW(),
			?,
			?,
			?,
			?,
			?,
			?,
			NOW()
		)`

		_, err = db.Handle.Exec(qInsertClockIn,
			"1",
			T_TransactionM_StaffID,
			T_TransactionM_CompanyID,
			&jamClockIn,
			T_TransactionCurrentLatitude,
			T_TransactionCurrentLongitude,
			T_TransactionCurrentDistance,
			&varFileName,
			&varProsesFotoSelfie,
			"Y",
		)

		// set status jika tidak error
		if err == nil {
			*ret.Status = "OK"
			*ret.Message = "Proses Absensi Masuk Berhasil"
		}

		// set status jika error
		if err != nil {
			*ret.Status = "ERR"
			*ret.Message = "ERROR : " + err.Error()
		}
	}

	return &ret, err
}

// fungsi untuk absen keluar clock out
func (transabsensi *TransAbsensiResponse) ClockOutAbsensi(T_TransactionM_StaffID string, T_TransactionM_CompanyID string, T_TransactionCurrentLatitude string, T_TransactionCurrentLongitude string, T_TransactionCurrentDistance string, T_TransactionSelfiePhoto string, token string, isSelfie string) (*model.TransAbsensiResponse, error) {
	// inisialisasi
	var err error
	var ret model.TransAbsensiResponse
	var varGetToken string
	var varGetM_StaffNIP string
	var varProsesFotoSelfie string
	var jamClockOut string
	var varFileName string

	// check user token
	qCheckTokenStaff := `SELECT 
	M_StaffToken,
	LOWER(M_StaffNIP) AS M_StaffNIP
	FROM m_staff
	WHERE M_StaffIsActive = 'Y'
	AND M_StaffToken = ?
	`

	rowCheckTokenStaff := db.Handle.QueryRow(
		qCheckTokenStaff,
		token,
	)
	db.LogSQL(qCheckTokenStaff)
	err = rowCheckTokenStaff.Scan(
		&varGetToken,
		&varGetM_StaffNIP,
	)

	if err != nil {
		log.Printf("Error m_staff select token: %v", err)
		log.Printf("Executing query: %s\n", qCheckTokenStaff)
		return nil, err
	}

	// check varGetToken jk M_StaffToken kosong
	if varGetToken == "" {
		log.Printf("Error Token Kosong, Silahkan Login Dulu: %v", err)
		log.Printf("Executing query: %s\n", qCheckTokenStaff)
		return nil, err
	}

	ret.Status = new(string)
	ret.Message = new(string)

	// lanjut proses absen
	if varGetToken != "" {

		// tanpa selfie T_TransactionSelfiePhoto di set kosong
		if isSelfie != "TRUE" {
			T_TransactionSelfiePhoto = ""
			varProsesFotoSelfie = ""

			// setting jam absen
			currentTime := time.Now()
			jam := currentTime.Hour()
			menit := currentTime.Minute()
			detik := currentTime.Second()

			jamClockOut = fmt.Sprintf("%02d:%02d:%02d", jam, menit, detik)
		}

		// selfie true
		if isSelfie == "TRUE" {

			// pecah string
			strToArrayFoto := strings.Split(T_TransactionSelfiePhoto, ",")

			// check apakah sudah sesuai apa belum
			if len(strToArrayFoto) == 0 {
				log.Printf("Eror Tidak Sesuai Format %v", err)
				return &ret, err
			}

			// jika sesuai ambil strToArrayFoto ke 1 atau index ke 1
			if len(strToArrayFoto) > 0 {
				base64DataFoto := strToArrayFoto[1]
				T_TransactionSelfiePhoto = base64DataFoto
			}

			currentTime := time.Now()

			// setting jam absen
			jam := currentTime.Hour()
			menit := currentTime.Minute()
			detik := currentTime.Second()

			jamClockOut = fmt.Sprintf("%02d:%02d:%02d", jam, menit, detik)

			formattedTime := currentTime.Format("2006-01-02_15_04_05")
			// buat nama file
			varProsesFotoSelfie = "clockout_" + varGetM_StaffNIP + "_" + formattedTime
			strPhoto := varProsesFotoSelfie + ".jpg"

			// folder upload file nya selfie_attachment akan otomatis sesuai bulan dan tahun
			folderName := currentTime.Format("200601")
			folder := "selfie_attachment/" + folderName + "/"
			photoPath := config.Data.Get("document") + folder

			log.Printf("documentPath: %s", photoPath)

			// create folder selfie_attachment jika belum ada
			if _, err := os.Stat(photoPath); errors.Is(err, os.ErrNotExist) {
				err = os.MkdirAll(photoPath, os.ModePerm.Perm())
				if err != nil {
					log.Printf("here %v", err)
					return &ret, err
				}
			}

			photoPath = photoPath + strPhoto

			// proses decode
			decodedByte, err := base64.StdEncoding.DecodeString(T_TransactionSelfiePhoto)

			if err != nil {
				log.Printf("here %v", err)
				return &ret, err
			}

			fs, err := os.Create(photoPath)
			if err != nil {
				log.Printf("here %v", err)
				return &ret, err
			}
			defer fs.Close()
			fs.Write(decodedByte)
			fs.Sync()

			varProsesFotoSelfie = "selfie_attachment/" + folderName + "/" + strPhoto
			varFileName = strPhoto
		}

		qInsertClockIn := `INSERT INTO t_transaction (
			T_TransactionM_AbsensiTypeID,
			T_TransactionM_StaffID,
			T_TransactionM_CompanyID,
			T_TransactionClockAbsensi,
			T_TransactionDate,
			T_TransactionCurrentLatitude,
			T_TransactionCurrentLongitude,
			T_TransactionCurrentDistance,
			T_TransactionFileName,
			T_TransactionSelfiePhotoPath,
			T_TransactionIsActive,
			T_TransactionCreated
		) VALUES (
			?,
			?,
			?,
			?,
			NOW(),
			?,
			?,
			?,
			?,
			?,
			?,
			NOW()
		)`

		_, err = db.Handle.Exec(qInsertClockIn,
			"2",
			T_TransactionM_StaffID,
			T_TransactionM_CompanyID,
			&jamClockOut,
			T_TransactionCurrentLatitude,
			T_TransactionCurrentLongitude,
			T_TransactionCurrentDistance,
			&varFileName,
			&varProsesFotoSelfie,
			"Y",
		)

		// set status jika tidak error
		if err == nil {
			*ret.Status = "OK"
			*ret.Message = "Proses Absensi Pulang Berhasil"
		}

		// set status jika error
		if err != nil {
			*ret.Status = "ERR"
			*ret.Message = "ERROR : " + err.Error()
		}
	}

	return &ret, err
}

// fungsi untuk get jam absen dan pulang
func (transabsensi *TransAbsensiCheckTimeAttendanceResponse) CheckTimeAttendance(M_StaffID string, M_CompanyID string, token string) (*model.TransAbsensiCheckTimeAttendanceResponse, error) {

	// inisialisasi
	var err error
	var ret model.TransAbsensiCheckTimeAttendanceResponse

	var var_jam_clock_in string
	var var_jam_clock_out string
	var var_is_absen_clock_in string = "FALSE"
	var var_is_absen_clock_out string = "FALSE"

	var varGetToken string
	var resultsArrayAttendance []struct {
		T_TransactionM_AbsensiTypeID string
		T_TransactionClockAbsensi    string
	}

	ret.Status = new(string)
	ret.Message = new(string)
	ret.JamClockIn = new(string)
	ret.JamClockOut = new(string)
	ret.IsAbsenClockIn = new(string)
	ret.IsAbsenClockOut = new(string)

	qCheckTokenStaff := `SELECT 
	M_StaffToken
	FROM m_staff
	WHERE M_StaffIsActive = 'Y'
	AND M_StaffToken = ?
	`

	rowCheckTokenStaff := db.Handle.QueryRow(
		qCheckTokenStaff,
		token,
	)

	db.LogSQL(qCheckTokenStaff)
	err = rowCheckTokenStaff.Scan(
		&varGetToken,
	)

	if err != nil {
		log.Printf("Error m_staff select token: %v", err)
		log.Printf("Executing query: %s\n", qCheckTokenStaff)
		return nil, err
	}

	// check varGetToken jk M_StaffToken kosong
	if varGetToken == "" {
		log.Printf("Error Token Kosong, Silahkan Login Dulu: %v", err)
		log.Printf("Executing query: %s\n", qCheckTokenStaff)
		return nil, err
	}

	// proses check attendance
	if varGetToken != "" {
		q := `SELECT T_TransactionM_AbsensiTypeID, 
		DATE_FORMAT(T_TransactionClockAbsensi,'%H:%i') as T_TransactionClockAbsensi
		FROM t_transaction
		WHERE T_TransactionIsActive = 'Y'
		AND T_TransactionM_AbsensiTypeID IN (1, 2)
		AND T_TransactionM_StaffID = ?
		AND T_TransactionM_CompanyID = ?
		AND T_TransactionDate BETWEEN DATE_FORMAT(NOW(), "%Y-%m-%d 01:00:00")
		AND DATE_FORMAT(NOW(), "%Y-%m-%d 23:00:00")
		ORDER BY T_TransactionM_AbsensiTypeID ASC`

		db.LogSQL(q, M_StaffID,
			M_CompanyID)

		rows, err := db.Handle.Query(
			q,
			M_StaffID,
			M_CompanyID)

		if err != nil {
			log.Printf("Error m_company select jam_clock_in dan jam_clock_out: %v", err)
			log.Printf("Executing query: %s\n", q)
			return nil, err
		}

		defer rows.Close()

		for rows.Next() {
			var resultTmp struct {
				T_TransactionM_AbsensiTypeID string
				T_TransactionClockAbsensi    string
			}

			if err := rows.Scan(
				&resultTmp.T_TransactionM_AbsensiTypeID,
				&resultTmp.T_TransactionClockAbsensi,
			); err != nil {
				log.Printf("Error scanning row: %v", err)
				return nil, err
			}

			// array push
			resultsArrayAttendance = append(resultsArrayAttendance, resultTmp)
		}

		if err := rows.Err(); err != nil {
			log.Printf("Error after iterating rows attendance : %v", err)
			return nil, err
		}

		// check length resultsArrayAttendance
		if len(resultsArrayAttendance) == 0 {
			log.Printf("Error Data Tidak Ada: %v", err)
			*ret.Status = "OK"
			*ret.Message = "Belum Ada Absen"
			*ret.JamClockIn = ""
			*ret.JamClockOut = ""
			*ret.IsAbsenClockIn = "FALSE"
			*ret.IsAbsenClockOut = "FALSE"
		}

		if len(resultsArrayAttendance) > 0 {
			for _, result := range resultsArrayAttendance {
				// clock in (absen masuk)
				if result.T_TransactionM_AbsensiTypeID == "1" {
					var_jam_clock_in = result.T_TransactionClockAbsensi

					if var_is_absen_clock_in != "" {
						var_is_absen_clock_in = "TRUE"
					}
				}

				// clock out (absen pulang)
				if result.T_TransactionM_AbsensiTypeID == "2" {
					var_jam_clock_out = result.T_TransactionClockAbsensi

					if var_is_absen_clock_out != "" {
						var_is_absen_clock_out = "TRUE"
					}
				}
			}

			*ret.Status = "OK"
			*ret.Message = "Sudah Ada Absen"
			*ret.JamClockIn = var_jam_clock_in
			*ret.JamClockOut = var_jam_clock_out
			*ret.IsAbsenClockIn = var_is_absen_clock_in
			*ret.IsAbsenClockOut = var_is_absen_clock_out
		}
	}

	return &ret, err
}

// fungsi untuk rekap kehadiran home screen
func (transabsensi *RekapKehadiranHomeScreen) RekapKehadiranHomeScreenV1(M_StaffID string, M_CompanyID string, token string) (*model.RekapKehadiranHomeScreen, error) {

	// inisialisasi
	var err error
	var ret model.RekapKehadiranHomeScreen

	var jumlah_saturday int = 0
	var jumlah_sunday int = 0
	var jumlah_hari_sampai_hari_ini int = 0

	var jumlah_hari_sampai_hari_ini_point_a int = 0
	var jumlah_hari_libur_sampai_hari_ini_point_b int = 0
	var jumlah_absen_sampai_hari_ini_point_c int = 0
	var total_ketidakhadiran int = 0
	var total_lembur_sampai_hari_ini int = 0

	// clear memory address
	ret.Kehadiran = new(string)
	ret.Lembur = new(string)
	ret.TidakHadir = new(string)
	ret.Status = new(string)
	ret.Message = new(string)

	// set value
	*ret.TidakHadir = "0"
	*ret.Kehadiran = "0"
	*ret.Lembur = "0"

	// query rekap lembur
	qLembur := `SELECT COUNT(T_TransactionLemburID) as total_lembur_sampai_hari_ini
	FROM t_transaction_lembur
	WHERE 
		T_TransactionLemburIsActive = 'Y'
		AND T_TransactionLemburM_StaffID = ?
		AND T_TransactionLemburM_CompanyID = ?
		AND T_TransactionLemburM_AbsensiTypeID = 5
		AND MONTH(T_TransactionTglLembur) = MONTH(CURDATE())`

	rowQLembur := db.Handle.QueryRow(
		qLembur,
		M_StaffID,
		M_CompanyID,
	)

	if err != nil {
		log.Printf("Error select count lembur: %v", err)
		log.Printf("Executing query: %s\n", qLembur)
		return nil, err
	}

	db.LogSQL(qLembur)
	err = rowQLembur.Scan(
		&total_lembur_sampai_hari_ini,
	)

	// query point A : jumlah hari sampai hari ini ( dalam bulan ini ) selain sabtu dan minggu
	qCountSaturday := `WITH RECURSIVE offdays as(
		SELECT 
		LAST_DAY(CURDATE()-INTERVAL 1 MONTH) + INTERVAL 1 DAY AS Date,
		DAYNAME(LAST_DAY(CURDATE()-INTERVAL 1 MONTH) + INTERVAL 1 DAY) AS DayName
		UNION ALL
		SELECT Date + INTERVAL 1 DAY, DAYNAME(Date + INTERVAL 1 DAY) 
		FROM offdays WHERE DATE < LAST_DAY(CURDATE()) 
		) SELECT count(*) as countSaturday FROM offdays where DAYNAME(DATE) = 'Saturday'`

	rowQCountSaturday := db.Handle.QueryRow(
		qCountSaturday,
	)

	if err != nil {
		log.Printf("Error select count jumlah saturday : %v", err)
		log.Printf("Executing query: %s\n", qCountSaturday)
		return nil, err
	}

	db.LogSQL(qCountSaturday)
	err = rowQCountSaturday.Scan(
		&jumlah_saturday,
	)

	qCountSunday := `WITH RECURSIVE offdays as(
		SELECT 
		LAST_DAY(CURDATE()-INTERVAL 1 MONTH) + INTERVAL 1 DAY AS Date,
		DAYNAME(LAST_DAY(CURDATE()-INTERVAL 1 MONTH) + INTERVAL 1 DAY) AS DayName
		UNION ALL
		SELECT Date + INTERVAL 1 DAY, DAYNAME(Date + INTERVAL 1 DAY) 
		FROM offdays WHERE DATE < LAST_DAY(CURDATE()) 
		) SELECT count(*) as countSaturday FROM offdays where DAYNAME(DATE) = 'Sunday'`

	rowQCountSunday := db.Handle.QueryRow(
		qCountSunday,
	)

	if err != nil {
		log.Printf("Error select count jumlah saturday : %v", err)
		log.Printf("Executing query: %s\n", qCountSunday)
		return nil, err
	}

	db.LogSQL(qCountSunday)
	err = rowQCountSunday.Scan(
		&jumlah_sunday,
	)

	qJumlahHariSampaiHariIni := `select timestampdiff(day,
		concat(year(now()),'-',month(now()),'-01'),
		date_add( concat(year(now()),'-',month(now()),'-01'), interval 1 month)) as jumlah_hari_sampai_hari_ini`

	rowqJumlahHariSampaiHariIni := db.Handle.QueryRow(
		qJumlahHariSampaiHariIni,
	)

	if err != nil {
		log.Printf("Error select count jumlah_hari_sampai_hari_ini: %v", err)
		log.Printf("Executing query: %s\n", qJumlahHariSampaiHariIni)
		return nil, err
	}

	db.LogSQL(qJumlahHariSampaiHariIni)
	err = rowqJumlahHariSampaiHariIni.Scan(
		&jumlah_hari_sampai_hari_ini,
	)

	// hitung point A
	jumlah_hari_sampai_hari_ini_point_a = jumlah_hari_sampai_hari_ini - jumlah_sunday - jumlah_saturday

	// query point B :  jumlah hari libur selain sabtu dan minggu sampai hari ini
	qPointB := `SELECT COUNT(M_LiburID) as jumlah_hari_libur_sampai_hari_ini_point_b
	FROM m_libur
	WHERE
	M_LiburIsActive = 'Y'
	AND M_LiburDate <= CURDATE()
	AND DAYOFWEEK(CURDATE()) BETWEEN 2 AND 6
	AND MONTH(M_LiburDate) = MONTH(CURDATE())`

	rowQPointB := db.Handle.QueryRow(
		qPointB,
	)

	if err != nil {
		log.Printf("Error select count jumlah_hari_libur_sampai_hari_ini_point_b: %v", err)
		log.Printf("Executing query: %s\n", qPointB)
		return nil, err
	}

	db.LogSQL(qPointB)
	err = rowQPointB.Scan(
		&jumlah_hari_libur_sampai_hari_ini_point_b,
	)

	// query point C : jumlah absen sampai hari ini ( bisa di lihat dari clock in )
	qPointC := `SELECT COUNT(T_TransactionID) as jumlah_absen_sampai_hari_ini_point_c
	FROM t_transaction
	WHERE 
		T_TransactionIsActive = 'Y'
		AND T_TransactionM_StaffID = ?
		AND T_TransactionM_CompanyID = ?
		AND (
			T_TransactionDate >= DATE_FORMAT(CURDATE(), '%Y-%m-01')
			OR T_TransactionDate = CURDATE()
		)
		AND (
			T_TransactionM_AbsensiTypeID = 1 
			AND (T_TransactionClockAbsensi != '00:00:00' OR T_TransactionClockAbsensi IS NOT NULL)
		)`

	rowQPointC := db.Handle.QueryRow(
		qPointC,
		M_StaffID,
		M_CompanyID,
	)

	if err != nil {
		log.Printf("Error select count jumlah_absen_sampai_hari_ini_point_c: %v", err)
		log.Printf("Executing query: %s\n", qPointC)
		return nil, err
	}

	db.LogSQL(qPointC)
	err = rowQPointC.Scan(
		&jumlah_absen_sampai_hari_ini_point_c,
	)

	total_ketidakhadiran = jumlah_hari_sampai_hari_ini_point_a - jumlah_hari_libur_sampai_hari_ini_point_b - jumlah_absen_sampai_hari_ini_point_c

	log.Printf("Executing jumlah_saturday: %s\n", strconv.Itoa(jumlah_saturday))
	log.Printf("Executing jumlah_sunday: %s\n", strconv.Itoa(jumlah_sunday))
	log.Printf("Executing jumlah_hari_sampai_hari_ini: %s\n", strconv.Itoa(jumlah_hari_sampai_hari_ini))

	log.Printf("Executing jumlah_hari_sampai_hari_ini_point_a: %s\n", strconv.Itoa(jumlah_hari_sampai_hari_ini_point_a))
	log.Printf("Executing jumlah_hari_libur_sampai_hari_ini_point_b: %s\n", strconv.Itoa(jumlah_hari_libur_sampai_hari_ini_point_b))
	log.Printf("Executing jumlah_absen_sampai_hari_ini_point_c: %s\n", strconv.Itoa(jumlah_absen_sampai_hari_ini_point_c))

	if total_ketidakhadiran != 0 {
		*ret.TidakHadir = strconv.Itoa(total_ketidakhadiran)
	}

	if jumlah_absen_sampai_hari_ini_point_c != 0 {
		*ret.Kehadiran = strconv.Itoa(jumlah_absen_sampai_hari_ini_point_c)
	}

	if total_lembur_sampai_hari_ini != 0 {
		*ret.Lembur = strconv.Itoa(total_lembur_sampai_hari_ini)
	}

	*ret.Status = "OK"
	*ret.Message = "Rekap Kehadiran Muncul"

	return &ret, err
}

func (transabsensi *RekapKehadiranHomeScreen) RekapKehadiranHomeScreen(M_StaffID string, M_CompanyID string, token string) (*model.RekapKehadiranHomeScreen, error) {

	// inisialisasi
	var err error
	var ret model.RekapKehadiranHomeScreen

	var jumlah_saturday int = 0
	var jumlah_sunday int = 0
	var jumlah_hari_sampai_hari_ini int = 0

	var jumlah_hari_sampai_hari_ini_point_a int = 0
	// var jumlah_hari_libur_sampai_hari_ini_point_b int = 0
	var jumlah_absen_sampai_hari_ini_point_c int = 0
	var total_ketidakhadiran int = 0
	var total_lembur_sampai_hari_ini int = 0

	// clear memory address
	ret.Kehadiran = new(string)
	ret.Lembur = new(string)
	ret.TidakHadir = new(string)
	ret.Status = new(string)
	ret.Message = new(string)

	// set value
	*ret.TidakHadir = "0"
	*ret.Kehadiran = "0"
	*ret.Lembur = "0"

	// query rekap lembur
	qLembur := `SELECT COUNT(T_TransactionLemburID) as total_lembur_sampai_hari_ini
	FROM t_transaction_lembur
	WHERE 
		T_TransactionLemburIsActive = 'Y'
		AND T_TransactionLemburM_StaffID = ?
		AND T_TransactionLemburM_CompanyID = ?
		AND T_TransactionLemburM_AbsensiTypeID = 5
		AND MONTH(T_TransactionTglLembur) = MONTH(CURDATE())`

	rowQLembur := db.Handle.QueryRow(
		qLembur,
		M_StaffID,
		M_CompanyID,
	)

	if err != nil {
		log.Printf("Error select count lembur: %v", err)
		log.Printf("Executing query: %s\n", qLembur)
		return nil, err
	}

	db.LogSQL(qLembur)
	err = rowQLembur.Scan(
		&total_lembur_sampai_hari_ini,
	)

	// query point A : jumlah hari sampai hari ini ( dalam bulan ini ) selain sabtu dan minggu
	qCountSaturday := `WITH RECURSIVE offdays as(
		SELECT 
			LAST_DAY(DATE_FORMAT(CURDATE(), '%Y-%m-01') - INTERVAL 1 MONTH) + INTERVAL 1 DAY AS Date,
			DAYNAME(LAST_DAY(DATE_FORMAT(CURDATE(), '%Y-%m-01') - INTERVAL 1 MONTH) + INTERVAL 1 DAY) AS DayName
			UNION ALL
			SELECT Date + INTERVAL 1 DAY, DAYNAME(Date + INTERVAL 1 DAY) 
			FROM offdays WHERE DATE < LAST_DAY(CURDATE()) 
			) 
		SELECT count(*) as countSaturday 
		FROM offdays where DAYNAME(DATE) = 'Saturday' 
		AND Date BETWEEN DATE_FORMAT(CURDATE(), '%Y-%m-01') AND CURDATE()`

	rowQCountSaturday := db.Handle.QueryRow(
		qCountSaturday,
	)

	if err != nil {
		log.Printf("Error select count jumlah saturday : %v", err)
		log.Printf("Executing query: %s\n", qCountSaturday)
		return nil, err
	}

	db.LogSQL(qCountSaturday)
	err = rowQCountSaturday.Scan(
		&jumlah_saturday,
	)

	qCountSunday := `WITH RECURSIVE offdays AS (
		SELECT 
			LAST_DAY(DATE_FORMAT(CURDATE(), '%Y-%m-01') - INTERVAL 1 MONTH) + INTERVAL 1 DAY AS Date,
			DAYNAME(LAST_DAY(DATE_FORMAT(CURDATE(), '%Y-%m-01') - INTERVAL 1 MONTH) + INTERVAL 1 DAY) AS DayName
				UNION ALL
				SELECT Date + INTERVAL 1 DAY, DAYNAME(Date + INTERVAL 1 DAY) 
				FROM offdays 
				WHERE DATE < LAST_DAY(CURDATE()) 
			)
		SELECT COUNT(*) AS countSunday 
		FROM offdays 
		WHERE DAYNAME(Date) = 'Sunday' AND Date BETWEEN DATE_FORMAT(CURDATE(), '%Y-%m-01') AND CURDATE()`

	rowQCountSunday := db.Handle.QueryRow(
		qCountSunday,
	)

	if err != nil {
		log.Printf("Error select count jumlah saturday : %v", err)
		log.Printf("Executing query: %s\n", qCountSunday)
		return nil, err
	}

	db.LogSQL(qCountSunday)
	err = rowQCountSunday.Scan(
		&jumlah_sunday,
	)

	qJumlahHariSampaiHariIni := `SELECT DATEDIFF(CURDATE(), DATE_FORMAT(CURDATE(), '%Y-%m-01') ) + 1 AS total_hari`

	rowqJumlahHariSampaiHariIni := db.Handle.QueryRow(
		qJumlahHariSampaiHariIni,
	)

	if err != nil {
		log.Printf("Error select count jumlah_hari_sampai_hari_ini: %v", err)
		log.Printf("Executing query: %s\n", qJumlahHariSampaiHariIni)
		return nil, err
	}

	db.LogSQL(qJumlahHariSampaiHariIni)
	err = rowqJumlahHariSampaiHariIni.Scan(
		&jumlah_hari_sampai_hari_ini,
	)

	// hitung point A
	jumlah_hari_sampai_hari_ini_point_a = jumlah_hari_sampai_hari_ini - jumlah_sunday - jumlah_saturday

	// query point C : jumlah absen sampai hari ini ( bisa di lihat dari clock in )
	qPointC := `SELECT COUNT(T_TransactionID) as jumlah_absen_sampai_hari_ini_point_c
	FROM t_transaction
	WHERE 
		T_TransactionIsActive = 'Y'
		AND T_TransactionM_StaffID = ?
		AND T_TransactionM_CompanyID = ?
		AND (
			T_TransactionDate >= DATE_FORMAT(CURDATE(), '%Y-%m-01')
			OR T_TransactionDate = CURDATE()
		)
		AND (
			T_TransactionM_AbsensiTypeID = 1 
			AND (T_TransactionClockAbsensi != '00:00:00' OR T_TransactionClockAbsensi IS NOT NULL)
		)`

	rowQPointC := db.Handle.QueryRow(
		qPointC,
		M_StaffID,
		M_CompanyID,
	)

	if err != nil {
		log.Printf("Error select count jumlah_absen_sampai_hari_ini_point_c: %v", err)
		log.Printf("Executing query: %s\n", qPointC)
		return nil, err
	}

	db.LogSQL(qPointC)
	err = rowQPointC.Scan(
		&jumlah_absen_sampai_hari_ini_point_c,
	)

	total_ketidakhadiran = jumlah_hari_sampai_hari_ini_point_a - jumlah_absen_sampai_hari_ini_point_c

	log.Printf("Executing jumlah_saturday: %s\n", strconv.Itoa(jumlah_saturday))
	log.Printf("Executing jumlah_sunday: %s\n", strconv.Itoa(jumlah_sunday))
	log.Printf("Executing jumlah_hari_sampai_hari_ini: %s\n", strconv.Itoa(jumlah_hari_sampai_hari_ini))

	log.Printf("Executing jumlah_hari_sampai_hari_ini_point_a: %s\n", strconv.Itoa(jumlah_hari_sampai_hari_ini_point_a))
	// log.Printf("Executing jumlah_hari_libur_sampai_hari_ini_point_b: %s\n", strconv.Itoa(jumlah_hari_libur_sampai_hari_ini_point_b))
	log.Printf("Executing jumlah_absen_sampai_hari_ini_point_c: %s\n", strconv.Itoa(jumlah_absen_sampai_hari_ini_point_c))

	if total_ketidakhadiran != 0 {
		*ret.TidakHadir = strconv.Itoa(total_ketidakhadiran)
	}

	if jumlah_absen_sampai_hari_ini_point_c != 0 {
		*ret.Kehadiran = strconv.Itoa(jumlah_absen_sampai_hari_ini_point_c)
	}

	if total_lembur_sampai_hari_ini != 0 {
		*ret.Lembur = strconv.Itoa(total_lembur_sampai_hari_ini)
	}

	*ret.Status = "OK"
	*ret.Message = "Rekap Kehadiran Muncul"

	return &ret, err
}
