package mcu_corporate_services

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

	"go.uber.org/zap"
)

type TabKelainanFisikServices struct {
	TabKelainanFisikStore db.AppStore
}

func NewTabKelainanFisikServices(store db.AppStore) *TabKelainanFisikServices {
	return &TabKelainanFisikServices{
		TabKelainanFisikStore: store,
	}
}

func (tkf *TabKelainanFisikServices) GetPieChartConf(title string, subtext string, data []models.SeriesData) (models.Piechart, error) {
	option := models.Piechart{
		Title: struct {
			Text    string `json:"text"`
			SubText string `json:"subtext"`
			Left    string `json:"left"`
		}{
			Text:    title,
			SubText: subtext,
			Left:    "center",
		},
		Tooltip: struct {
			Trigger string `json:"trigger"`
		}{
			Trigger: "item",
		},
		Legend: struct {
			Top    string `json:"top"`
			Left   string `json:"left"`
			Orient string `json:"orient"`
			Height int    `json:"height"`
		}{
			Top:    "bottom",
			Left:   "center",
			Orient: "vertical",
			Height: 75,
		},
		Series: []models.Series{
			{
				Label: struct {
					Position  string `json:"position"`
					Formatter string `json:"formatter"`
				}{
					Position:  "inner",
					Formatter: "{d}%",
				},
				Name:   "Access From",
				Type:   "pie",
				Radius: []string{"20%", "50%"},
				ItemStyle: struct {
					BorderRadius int    `json:"borderRadius"`
					BorderColor  string `json:"borderColor"`
					BorderWidth  int    `json:"borderWidth"`
				}{
					BorderRadius: 10,
					BorderColor:  "#fff",
					BorderWidth:  2,
				},
				Data: data,
				Emphasis: struct {
					ItemStyle struct {
						ShadowBlur    int    `json:"shadowBlur"`
						ShadowOffsetX int    `json:"shadowOffsetX"`
						ShadowColor   string `json:"shadowColor"`
					} `json:"itemStyle"`
				}{
					ItemStyle: struct {
						ShadowBlur    int    `json:"shadowBlur"`
						ShadowOffsetX int    `json:"shadowOffsetX"`
						ShadowColor   string `json:"shadowColor"`
					}{
						ShadowBlur:    10,
						ShadowOffsetX: 0,
						ShadowColor:   "rgba(0, 0, 0, 0.5)",
					},
				},
			},
		},
	}

	return option, nil
}

func (tkf *TabKelainanFisikServices) GetBarChartConf(title string, data models.BarDataset) (models.Barchart, error) {
	isEmpty := ""
	if len(data.Source) <= 1 {
		isEmpty = "Data tidak ditemukan"
	}

	option := models.Barchart{}
	option.Title = struct {
		Text string "json:\"text\""
		Left string `json:"left"`
	}{
		Text: title,
		Left: "center",
	}
	option.Dataset = data
	option.Grid.ContainLabel = true
	option.XAxis.Name = "person"
	option.YAxis.Type = "category"
	option.VisualMap.Orient = "horizontal"
	option.VisualMap.Left = "center"
	option.VisualMap.Min = 0
	option.VisualMap.Max = 10
	option.VisualMap.Show = false
	option.VisualMap.Dimension = 0
	option.VisualMap.InRange.Color = []string{"#035bff", "#42aaf5", "#00eaf2"}
	option.Series = []struct {
		Label struct {
			Position  string "json:\"position\""
			Show      bool   "json:\"show\""
			Formatter string "json:\"formatter\""
		} "json:\"label\""
		Type   string "json:\"type\""
		Encode struct {
			X string "json:\"x\""
			Y string "json:\"y\""
		} "json:\"encode\""
	}{
		{
			Label: struct {
				Position  string "json:\"position\""
				Show      bool   "json:\"show\""
				Formatter string "json:\"formatter\""
			}{
				Position:  "right",
				Show:      true,
				Formatter: "{@[3]} %",
			},
			Type: "bar",
			Encode: struct {
				X string "json:\"x\""
				Y string "json:\"y\""
			}{
				X: "amount",
				Y: "product",
			},
		},
	}
	option.Tooltip = struct {
		Trigger     string "json:\"trigger\""
		AxisPointer struct {
			Type string "json:\"type\""
		} "json:\"axisPointer\""
	}{
		Trigger: "axis",
		AxisPointer: struct {
			Type string "json:\"type\""
		}{
			Type: "shadow",
		},
	}
	option.Graphic = struct {
		Type  string "json:\"type\""
		Left  string "json:\"left\""
		Top   string "json:\"top\""
		Style struct {
			Text       string "json:\"text\""
			FontSize   string "json:\"fontSize\""
			FontWeight string "json:\"fontWeight\""
		} "json:\"style\""
	}{
		Type: "text",
		Left: "center",
		Top:  "middle",
		Style: struct {
			Text       string "json:\"text\""
			FontSize   string "json:\"fontSize\""
			FontWeight string "json:\"fontWeight\""
		}{
			Text:       isEmpty,
			FontSize:   "15",
			FontWeight: "bold",
		},
	}

	return option, nil
}

func (tkf *TabKelainanFisikServices) GetKelainanFisikPresentase(mcuID string) (models.Barchart, error) {
	var option models.Barchart
	var data []models.KelainanGlobalFisikModel

	q := `
		SELECT Mcu_KelainanName,
		count(distinct T_OrderHeaderID) as total
		FROM t_kelainan_fisik
		JOIN t_orderheader ON T_KelainanFiskT_OrderHeaderID = T_OrderHeaderID
		JOIN mcu_summaryfisik ON T_KelainanFiskMcu_SummaryFisikID = Mcu_SummaryFisikID AND 
		Mcu_SummaryFisikID NOT IN (63,67,68,69,70,71,72,73)
		join mcu_kelainan on Mcu_SummaryFisikMcu_KelainanID = Mcu_KelainanID
		join mcu_kelainangroup on Mcu_KelainanMcu_KelainanGroupID = Mcu_KelainanGroupID
		where T_KelainanFiskIsActive = 'Y' and T_OrderHeaderMgm_McuID = ? AND
		Mcu_KelainanClasification NOT IN ('who','kemenkes','JNC-VIII','ESC/ESH')
		group by Mcu_KelainanID 
		ORDER BY total DESC
		LIMIT 10
	`
	if err := dbx.Handlex.Select(&data, q, mcuID); err != nil {
		return option, fmt.Errorf("error get data kelainan fisik: %v", err)
	}

	var jumlahPeserta models.TotalPesertaModel
	q = `
		SELECT 
		COUNT(distinct(T_OrderHeaderID)) as peserta,
		COUNT( distinct(Mcu_PreregisterPatientsM_PatientID)) as total
		FROM mcu_preregister_patients
		LEFT JOIN t_orderheader ON Mcu_PreregisterPatientsT_OrderHeaderID = T_OrderHeaderID AND
		T_OrderHeaderIsActive = 'Y'
		WHERE
		Mcu_PreregisterPatientsMgm_McuID = ? AND
		Mcu_PreregisterPatientsIsActive = 'Y'
	`
	if err := dbx.Handlex.Get(&jumlahPeserta, q, mcuID); err != nil {
		return option, fmt.Errorf("error get jumlah peserta %v", err)
	}

	title := "Kelainan Fisik (10 Terbesar)"
	chartData := models.BarDataset{
		Source: [][]interface{}{
			{"score", "amount", "product", "percentage"},
		},
	}

	for i, d := range data {
		percentage := float64(d.Total) / float64(jumlahPeserta.Peserta) * 100
		roundedPercentage := math.Round(percentage*100) / 100
		percentStr := strconv.FormatFloat(roundedPercentage, 'f', -1, 64)
		newText := utils.SplitStrings(d.Mcu_KelainanName, 2)
		chartData.Source = append(chartData.Source, []interface{}{
			i, d.Total, newText, percentStr,
		})
	}

	option, err := tkf.GetBarChartConf(title, chartData)
	if err != nil {
		return option, fmt.Errorf("error insert data to barchart %v", err)
	}
	return option, nil
}

func (tkf *TabKelainanFisikServices) GetKelainanFisikBMI(mcuID string) (models.Piechart, error) {
	logger, _ := zap.NewProduction()
	var option models.Piechart
	var data []models.KelainanFisikDataModel

	q := `
		SELECT Mcu_KelainanName as test,
		Mcu_KelainanClasification,
		count(distinct orderkel.T_OrderHeaderID)  as total
		FROM mcu_kelainan
		JOIN mcu_summaryfisik ON Mcu_SummaryFisikMcu_KelainanID = Mcu_KelainanID AND 
		Mcu_SummaryFisikIsActive = 'Y'
		LEFT JOIN t_kelainan_fisik ON T_KelainanFiskMcu_SummaryFisikID = Mcu_SummaryFisikID AND
		T_KelainanFiskIsActive= 'Y'
		LEFT JOIN t_orderheader orderkel ON T_KelainanFiskT_OrderHeaderID = orderkel.T_OrderHeaderID AND
		orderkel.T_OrderHeaderIsActive = 'Y' AND orderkel.T_OrderHeaderMgm_McuID = ?
		WHERE
		Mcu_KelainanIsActive = 'Y' AND Mcu_KelainanClasification = 'asia_pacific'
		group by Mcu_KelainanID
		UNION
		SELECT 'Normal' as test,
		'asia_pacific' as Mcu_KelainanClasification,
		ifnull(count(distinct T_OrderHeaderID) - summary_total_kelainan_bmi(?), 0) as total
		FROM t_orderheader
		WHERE
		T_OrderHeaderMgm_McuID = ? AND T_OrderHeaderIsActive = 'Y'
		group by T_OrderHeaderMgm_McuID	
	`

	if err := dbx.Handlex.Select(&data, q, mcuID, mcuID, mcuID); err != nil {
		return option, fmt.Errorf("error get data kel fisik bmi %v", err)
	}
	defer logger.Sync()
	logger.Info("resp data", zap.Any("data", data))

	title := "Status Index Masa Tubuh (BMI)"
	subtext := ""
	chartData := []models.SeriesData{}

	if data != nil {
		for _, d := range data {
			chartData = append(chartData, models.SeriesData{
				Value: d.Total,
				Name:  d.Test + ": " + strconv.Itoa(d.Total) + " Peserta",
			})
		}
	} else {
		chartData = append(chartData, models.SeriesData{Value: 0, Name: "No Data"})
	}

	option, err := tkf.GetPieChartConf(title, subtext, chartData)
	if err != nil {
		return option, fmt.Errorf("error get & insert data into chart: %v", err)
	}

	return option, nil
}

func (tkf *TabKelainanFisikServices) GetKelainanFisikHipertensi(mcuID string) (models.Piechart, error) {
	logger, _ := zap.NewProduction()
	var option models.Piechart
	var data []models.KelainanFisikDataModel

	q := `
		SELECT Mcu_KelainanName as test,
		Mcu_KelainanClasification,
		count(distinct orderkel.T_OrderHeaderID)  as total
		FROM mcu_kelainan
		JOIN mcu_summaryfisik ON Mcu_SummaryFisikMcu_KelainanID = Mcu_KelainanID AND 
		Mcu_SummaryFisikIsActive = 'Y'
		LEFT JOIN t_kelainan_fisik ON T_KelainanFiskMcu_SummaryFisikID = Mcu_SummaryFisikID AND
		T_KelainanFiskIsActive= 'Y'
		LEFT JOIN t_orderheader orderkel ON T_KelainanFiskT_OrderHeaderID = orderkel.T_OrderHeaderID AND
		orderkel.T_OrderHeaderIsActive = 'Y' AND orderkel.T_OrderHeaderMgm_McuID = ?
		WHERE
		Mcu_KelainanIsActive = 'Y' AND Mcu_KelainanClasification = 'JNC-VII'
		group by Mcu_KelainanID
		UNION
		SELECT 'Normal' as test,
		'JNC-VII' as Mcu_KelainanClasification,
		IFNULL(COUNT(T_OrderHeaderID) - summary_total_kelainan_hipertensi(?), 0) as total 
		FROM t_orderheader
		WHERE
		T_OrderHeaderMgm_McuID = ? AND T_OrderHeaderIsActive = 'Y'
		group by T_OrderHeaderMgm_McuID	
	`

	if err := dbx.Handlex.Select(&data, q, mcuID, mcuID, mcuID); err != nil {
		return option, fmt.Errorf("error get data kel fisik hipertensi: %v", err)
	}
	defer logger.Sync()
	logger.Info("resp data", zap.Any("data", data))

	title := "Kriteria Hipertensi"
	subtext := ""
	chartData := []models.SeriesData{}

	if data != nil {
		for _, d := range data {
			chartData = append(chartData, models.SeriesData{
				Value: d.Total,
				Name:  d.Test + ": " + strconv.Itoa(d.Total) + " Peserta",
			})
		}
	} else {
		chartData = append(chartData, models.SeriesData{Value: 0, Name: "No Data"})
	}

	option, err := tkf.GetPieChartConf(title, subtext, chartData)
	if err != nil {
		return option, fmt.Errorf("error get and insert data into piechart : %v", err)
	}

	return option, nil
}

func (tkf *TabKelainanFisikServices) GetKelainanFisikRefraksi(mcuID string) (models.Piechart, error) {
	var option models.Piechart
	var data []models.KelainanFisikDataModel

	q := `
		SELECT Mcu_KelainanName as test,
		count(distinct orderkel.T_OrderHeaderID)  as total
		FROM mcu_kelainan
		JOIN mcu_summaryfisik ON Mcu_SummaryFisikMcu_KelainanID = Mcu_KelainanID AND 
		Mcu_SummaryFisikIsActive = 'Y'
		LEFT JOIN t_kelainan_fisik ON T_KelainanFiskMcu_SummaryFisikID = Mcu_SummaryFisikID AND
		T_KelainanFiskIsActive= 'Y'
		LEFT JOIN t_orderheader orderkel ON T_KelainanFiskT_OrderHeaderID = orderkel.T_OrderHeaderID AND
		orderkel.T_OrderHeaderIsActive = 'Y' AND orderkel.T_OrderHeaderMgm_McuID = ?
		WHERE
		Mcu_KelainanIsActive = 'Y' AND Mcu_KelainanID IN (24,25)
		group by Mcu_KelainanID
		UNION
		SELECT 'Normal' as test,
		IFNULL(count(distinct T_OrderHeaderID) - summary_total_kelainan_visus(?), 0) as total
		FROM t_orderheader
		WHERE
		T_OrderHeaderMgm_McuID = ? AND T_OrderHeaderIsActive = 'Y'
		group by T_OrderHeaderMgm_McuID	
	`

	if err := dbx.Handlex.Select(&data, q, mcuID, mcuID, mcuID); err != nil {
		return option, fmt.Errorf("error get data kel fisik refraksi: %v", err)
	}

	title := "Refraksi"
	subtext := ""
	chartData := []models.SeriesData{}

	if data != nil {
		for _, d := range data {
			chartData = append(chartData, models.SeriesData{
				Value: d.Total,
				Name:  d.Test + ": " + strconv.Itoa(d.Total) + " Peserta",
			})
		}
	} else {
		chartData = append(chartData, models.SeriesData{Value: 0, Name: "No Data"})
	}

	option, err := tkf.GetPieChartConf(title, subtext, chartData)
	if err != nil {
		return option, fmt.Errorf("error get and insert data to chart: %v", err)
	}

	return option, nil
}

func (tkf *TabKelainanFisikServices) GetKelFisikAlkohol(mcuID string) (models.Piechart, error) {
	var option models.Piechart
	var data []models.KelainanFisikDataModel

	q := `
		SELECT 
		Mcu_KelainanName as test, 
		COUNT( distinct T_OrderHeaderID) as total
		FROM mcu_kelainan
		JOIN mcu_summaryfisik ON Mcu_SummaryFisikMcu_KelainanID = Mcu_KelainanID AND 
		Mcu_KelainanIsActive = 'Y' AND Mcu_KelainanID IN (117,118,119)
		LEFT JOIN t_kelainan_fisik ON T_KelainanFiskMcu_SummaryFisikID = Mcu_SummaryFisikID AND 
		T_KelainanFiskIsActive = 'Y'
		LEFT JOIN so_resultentry ON T_KelainanFiskSo_ResultEntryID = So_ResultEntryID AND 
		So_ResultEntryIsActive = 'Y'
		LEFT JOIN so_resultentry_fisik_umum ON So_ResultEntryFisikUmumSo_ResultEntryID = So_ResultEntryID AND
		So_ResultEntryFisikUmumIsActive = 'Y'
		LEFT JOIN t_orderheader ON So_ResultEntryT_OrderHeaderID = T_OrderHeaderID AND 
		T_OrderHeaderMgm_McuID =  ?
		group by Mcu_KelainanID
	`

	if err := dbx.Handlex.Select(&data, q, mcuID); err != nil {
		return option, fmt.Errorf("error get data kel fisik konsumsi alkohol: %v", err)
	}

	title := "Konsumsi Alkohol"
	subtext := ""
	chartData := []models.SeriesData{}

	if data != nil {
		for _, d := range data {
			chartData = append(chartData, models.SeriesData{
				Value: d.Total,
				Name:  d.Test + ": " + strconv.Itoa(d.Total) + " Peserta",
			})
		}
	} else {
		chartData = append(chartData, models.SeriesData{Value: 0, Name: "No Data"})
	}

	option, err := tkf.GetPieChartConf(title, subtext, chartData)
	if err != nil {
		return option, fmt.Errorf("error get and insert data to chart: %v", err)
	}

	return option, nil
}

func (tkf *TabKelainanFisikServices) GetKelFisikMerokok(mcuID string) (models.Piechart, error) {
	var option models.Piechart
	var data []models.KelainanFisikDataModel

	q := `
		SELECT Mcu_KelainanName as test, COUNT( distinct T_OrderHeaderID) as total
		FROM mcu_kelainan
		JOIN mcu_summaryfisik ON Mcu_SummaryFisikMcu_KelainanID = Mcu_KelainanID AND 
		Mcu_KelainanIsActive = 'Y' AND Mcu_KelainanID IN (120,121,122)
		LEFT JOIN t_kelainan_fisik ON T_KelainanFiskMcu_SummaryFisikID = Mcu_SummaryFisikID AND 
		T_KelainanFiskIsActive = 'Y'
		LEFT JOIN so_resultentry ON T_KelainanFiskSo_ResultEntryID = So_ResultEntryID AND 
		So_ResultEntryIsActive = 'Y'
		LEFT JOIN so_resultentry_fisik_umum ON So_ResultEntryFisikUmumSo_ResultEntryID = So_ResultEntryID AND
		So_ResultEntryFisikUmumIsActive = 'Y'
		LEFT JOIN t_orderheader ON So_ResultEntryT_OrderHeaderID = T_OrderHeaderID AND 
		T_OrderHeaderMgm_McuID = ?
		group by Mcu_KelainanID
	`
	if err := dbx.Handlex.Select(&data, q, mcuID); err != nil {
		return option, fmt.Errorf("error get data kel fisik merokok %v", err)
	}

	title := "Merokok"
	subtext := ""
	chartData := []models.SeriesData{}

	if data != nil {
		for _, d := range data {
			chartData = append(chartData, models.SeriesData{
				Value: d.Total,
				Name:  d.Test + ": " + strconv.Itoa(d.Total) + " Peserta",
			})
		}
	} else {
		chartData = append(chartData, models.SeriesData{Value: 0, Name: "No Data"})
	}

	option, err := tkf.GetPieChartConf(title, subtext, chartData)
	if err != nil {
		return option, fmt.Errorf("error get and insert data into chart %v", err)
	}

	return option, nil
}

func (tkf *TabKelainanFisikServices) GetKelFisikOlahraga(mcuID string) (models.Piechart, error) {
	var option models.Piechart
	var data []models.KelainanFisikDataModel

	q := `
		SELECT Mcu_KelainanName as test, COUNT( distinct T_OrderHeaderID) as total
		FROM mcu_kelainan
		JOIN mcu_summaryfisik ON Mcu_SummaryFisikMcu_KelainanID = Mcu_KelainanID AND 
		Mcu_KelainanIsActive = 'Y' AND Mcu_KelainanID IN (123,124)
		LEFT JOIN t_kelainan_fisik ON T_KelainanFiskMcu_SummaryFisikID = Mcu_SummaryFisikID AND 
		T_KelainanFiskIsActive = 'Y'
		LEFT JOIN so_resultentry ON T_KelainanFiskSo_ResultEntryID = So_ResultEntryID AND 
		So_ResultEntryIsActive = 'Y'
		LEFT JOIN so_resultentry_fisik_umum ON So_ResultEntryFisikUmumSo_ResultEntryID = So_ResultEntryID AND
		So_ResultEntryFisikUmumIsActive = 'Y'
		LEFT JOIN t_orderheader ON So_ResultEntryT_OrderHeaderID = T_OrderHeaderID AND 
		T_OrderHeaderMgm_McuID = ?
		group by Mcu_KelainanID
	`
	if err := dbx.Handlex.Select(&data, q, mcuID); err != nil {
		return option, fmt.Errorf("error get data kel fisik olahraga %v", err)
	}

	title := "Olahraga"
	subtext := ""
	chartData := []models.SeriesData{}

	if data != nil {
		for _, d := range data {
			chartData = append(chartData, models.SeriesData{
				Value: d.Total,
				Name:  d.Test + ": " + strconv.Itoa(d.Total) + " Peserta",
			})
		}
	} else {
		chartData = append(chartData, models.SeriesData{Value: 0, Name: "No Data"})
	}

	option, err := tkf.GetPieChartConf(title, subtext, chartData)
	if err != nil {
		return option, fmt.Errorf("error get and insert data to chart %v", err)
	}

	return option, nil
}

func (tkf *TabKelainanFisikServices) GetChartRenderFisik(mcuID string) ([]models.McuTabModels, error) {
	var ret []models.McuTabModels

	q := `
	SELECT
	Mcu_ImageGrafikGroupResult,
	Mcu_ImageGrafikGroupMenu,
	Mcu_ImageGrafikName,
	Mcu_ImageGrafikJsonRender
	FROM mgm_mcugrafik
	JOIN mcu_image_grafik ON Mcu_ImageGrafikID = Mgm_McuGrafikMcu_ImageGrafikID
	WHERE Mgm_McuGrafikMgm_McuID = ?
	AND Mcu_ImageGrafikGroupResult = "FISIK"
	AND Mgm_McuGrafikIsActive = 'Y'
	ORDER BY Mcu_ImageGrafikID
	`
	if err := dbx.Handlex.Select(&ret, q, mcuID); err != nil {
		return ret, fmt.Errorf("error get data tab peserta: %v", err)
	}

	return ret, nil
}
