package templates

import (
	"bytes"
	"fmt"
	"strings"

	. "primesys_email/src/models/report"

	"github.com/xuri/excelize/v2"
)

const (
	fenceIn  = "IN"
	fenceOut = "OUT"
)

func CreateGateMitraReportExcel(reports []DivisionTripReportModel, divisionName string, reportDate string) ([]byte, error) {
	f := excelize.NewFile()
	defer func() {
		_ = f.Close()
	}()

	const sheet = "GateMitra Report"

	defaultSheet := f.GetSheetName(0)
	if err := f.SetSheetName(defaultSheet, sheet); err != nil {
		return nil, err
	}

	// Column widths.
	widths := []float64{10, 30, 24, 16, 16}
	for i, width := range widths {
		col, err := excelize.ColumnNumberToName(i + 1)
		if err != nil {
			return nil, err
		}
		if err := f.SetColWidth(sheet, col, col, width); err != nil {
			return nil, err
		}
	}

	// Styles.
	titleStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   13,
			Bold:   true,
			Color:  "1A1A1A",
		},
		Alignment: &excelize.Alignment{
			Horizontal: "center",
			Vertical:   "center",
		},
	})
	if err != nil {
		return nil, err
	}

	dateStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   13,
			Bold:   true,
			Color:  "5C70C4",
		},
		Alignment: &excelize.Alignment{
			Horizontal: "center",
			Vertical:   "center",
		},
	})
	if err != nil {
		return nil, err
	}

	metaLabelStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   8,
			Color:  "555555",
		},
	})
	if err != nil {
		return nil, err
	}

	metaValueStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   8,
			Bold:   true,
			Color:  "1A1A1A",
		},
	})
	if err != nil {
		return nil, err
	}

	headerStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   8,
			Bold:   true,
			Color:  "FFFFFF",
		},
		Fill: excelize.Fill{
			Type:    "pattern",
			Color:   []string{"015958"},
			Pattern: 1,
		},
		Alignment: &excelize.Alignment{
			Horizontal: "center",
			Vertical:   "center",
			WrapText:   true,
		},
		Border: gateMitraBorders("014545"),
	})
	if err != nil {
		return nil, err
	}

	oddStyles, err := gateMitraDataStyles(f, "FFFFFF")
	if err != nil {
		return nil, err
	}

	evenStyles, err := gateMitraDataStyles(f, "F4FAFA")
	if err != nil {
		return nil, err
	}

	// Row 1: title and date.
	if err := f.SetRowHeight(sheet, 1, 22); err != nil {
		return nil, err
	}

	if err := f.SetCellValue(sheet, "A1", "GATEMITRA REPORT"); err != nil {
		return nil, err
	}
	if err := f.SetCellStyle(sheet, "A1", "A1", titleStyle); err != nil {
		return nil, err
	}
	if err := f.MergeCell(sheet, "A1", "C1"); err != nil {
		return nil, err
	}

	if err := f.SetCellValue(sheet, "D1", reportDate); err != nil {
		return nil, err
	}
	if err := f.SetCellStyle(sheet, "D1", "D1", dateStyle); err != nil {
		return nil, err
	}
	if err := f.MergeCell(sheet, "D1", "E1"); err != nil {
		return nil, err
	}

	// Row 2: metadata.
	if err := f.SetRowHeight(sheet, 2, 16); err != nil {
		return nil, err
	}

	setGateMitraMetaPair(
		f, sheet, "A2", "B2",
		"Division: ", divisionName+"    ",
		metaLabelStyle, metaValueStyle,
	)

	setGateMitraMetaPair(
		f, sheet, "C2", "D2",
		"Date: ", reportDate+"    ",
		metaLabelStyle, metaValueStyle,
	)

	setGateMitraMetaPair(
		f, sheet, "E2", "F2",
		"Total Devices: ", fmt.Sprint(len(reports)),
		metaLabelStyle, metaValueStyle,
	)

	// Row 3 is the spacer.

	// Row 4: headers.
	headers := []string{
		"Sr.No",
		"Name",
		"Imei No",
		"IN Count",
		"OUT Count",
	}

	const headerRow = 4

	if err := f.SetRowHeight(sheet, headerRow, 18); err != nil {
		return nil, err
	}

	for i, header := range headers {
		cell, err := excelize.CoordinatesToCellName(i+1, headerRow)
		if err != nil {
			return nil, err
		}

		if err := f.SetCellValue(sheet, cell, header); err != nil {
			return nil, err
		}
		if err := f.SetCellStyle(sheet, cell, cell, headerStyle); err != nil {
			return nil, err
		}
	}

	// Rows 5 onward: report data.
	for i, report := range reports {
		row := i + 5

		if err := f.SetRowHeight(sheet, row, 16); err != nil {
			return nil, err
		}

		styles := oddStyles
		if i%2 != 0 {
			styles = evenStyles
		}

		values := []string{
			fmt.Sprint(i + 1),
			gateMitraDefaultString(report.DeviceName),
			gateMitraIMEI(report.DeviceImei),
			fmt.Sprint(countFenceStatus(report.TripList, fenceIn)),
			fmt.Sprint(countFenceStatus(report.TripList, fenceOut)),
		}

		for col, value := range values {
			cell, err := excelize.CoordinatesToCellName(col+1, row)
			if err != nil {
				return nil, err
			}

			if err := f.SetCellValue(sheet, cell, value); err != nil {
				return nil, err
			}

			style := styles[1] // Normal cell.
			if col == 1 {
				style = styles[0] // Name cell.
			}

			if err := f.SetCellStyle(sheet, cell, cell, style); err != nil {
				return nil, err
			}
		}
	}

	// Write workbook to memory.
	var buf bytes.Buffer
	if err := f.Write(&buf); err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

// Count matching fence statuses, ignoring case.
func countFenceStatus(
	trips []TripReportStatusModel,
	status string,
) int {
	count := 0

	for _, trip := range trips {
		// missing fence status is not counted
		if trip.FenceStatus != nil && strings.EqualFold(*trip.FenceStatus, status) {
			count++
		}
	}

	return count
}

// Data styles: [0] = name cell, [1] = normal cell.
func gateMitraDataStyles(
	f *excelize.File,
	background string,
) ([]int, error) {
	nameStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   8,
			Bold:   true,
			Color:  "015958",
		},
		Fill: excelize.Fill{
			Type:    "pattern",
			Color:   []string{background},
			Pattern: 1,
		},
		Alignment: &excelize.Alignment{
			Horizontal: "left",
			Vertical:   "center",
		},
		Border: gateMitraBorders("DDDDEE"),
	})
	if err != nil {
		return nil, err
	}

	cellStyle, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "Arial",
			Size:   8,
			Color:  "222222",
		},
		Fill: excelize.Fill{
			Type:    "pattern",
			Color:   []string{background},
			Pattern: 1,
		},
		Alignment: &excelize.Alignment{
			Horizontal: "center",
			Vertical:   "center",
		},
		Border: gateMitraBorders("DDDDEE"),
	})
	if err != nil {
		return nil, err
	}

	return []int{nameStyle, cellStyle}, nil
}

func gateMitraBorders(color string) []excelize.Border {
	return []excelize.Border{
		{Type: "left", Color: color, Style: 1},
		{Type: "right", Color: color, Style: 1},
		{Type: "top", Color: color, Style: 1},
		{Type: "bottom", Color: color, Style: 1},
	}
}

func setGateMitraMetaPair(
	f *excelize.File,
	sheet string,
	labelCell string,
	valueCell string,
	label string,
	value string,
	labelStyle int,
	valueStyle int,
) {
	_ = f.SetCellValue(sheet, labelCell, label)
	_ = f.SetCellStyle(sheet, labelCell, labelCell, labelStyle)

	_ = f.SetCellValue(sheet, valueCell, value)
	_ = f.SetCellStyle(sheet, valueCell, valueCell, valueStyle)
}

func gateMitraDefaultString(value *string) string {
	if value == nil || strings.TrimSpace(*value) == "" {
		return "-"
	}
	return *value
}

func gateMitraIMEI(value *int64) string {
	if value == nil {
		return "-"
	}
	return fmt.Sprint(*value)
}
