package analytic

import (
	"encoding/csv"
	"encoding/json"
	"log"
	"net/http"
	"strconv"
	"strings"
	"time"

	"imuslab.com/zoraxy/mod/statistic"
	"imuslab.com/zoraxy/mod/utils"
)

func (d *DataLoader) HandleSummaryList(w http.ResponseWriter, r *http.Request) {
	entries, err := d.Database.ListTable("stats")
	if err != nil {
		utils.SendErrorResponse(w, "unable to load data from database")
		return
	}

	entryDates := []string{}
	for _, keypairs := range entries {
		entryDates = append(entryDates, string(keypairs[0]))
	}

	js, _ := json.MarshalIndent(entryDates, "", " ")
	utils.SendJSONResponse(w, string(js))
}

func (d *DataLoader) HandleLoadTargetDaySummary(w http.ResponseWriter, r *http.Request) {
	day, err := utils.GetPara(r, "id")
	if err != nil {
		utils.SendErrorResponse(w, "id cannot be empty")
		return
	}

	if strings.Contains(day, "-") {
		//Must be underscore
		day = strings.ReplaceAll(day, "-", "_")
	}

	if !statistic.IsBeforeToday(day) {
		utils.SendErrorResponse(w, "given date is in the future")
		return
	}

	var targetDailySummary statistic.DailySummaryExport

	if day == time.Now().Format("2006_01_02") {
		targetDailySummary = *d.StatisticCollector.GetExportSummary()
	} else {
		//Not today data
		err = d.Database.Read("stats", day, &targetDailySummary)
		if err != nil {
			utils.SendErrorResponse(w, "target day data not found")
			return
		}
	}

	js, _ := json.Marshal(targetDailySummary)
	utils.SendJSONResponse(w, string(js))
}

func (d *DataLoader) HandleLoadTargetRangeSummary(w http.ResponseWriter, r *http.Request) {
	start, end, err := d.GetStartAndEndDatesFromRequest(r)
	if err != nil {
		utils.SendErrorResponse(w, err.Error())
		return
	}

	dailySummaries, _, err := d.GetAllStatisticSummaryInRange(start, end)
	if err != nil {
		utils.SendErrorResponse(w, err.Error())
		return
	}

	//Merge the summaries into one
	mergedSummary := mergeDailySummaryExports(dailySummaries)

	js, _ := json.Marshal(struct {
		Summary *statistic.DailySummaryExport
		Records []*statistic.DailySummaryExport
	}{
		Summary: mergedSummary,
		Records: dailySummaries,
	})

	utils.SendJSONResponse(w, string(js))
}

// Handle exporting of a given range statistics
func (d *DataLoader) HandleRangeExport(w http.ResponseWriter, r *http.Request) {
	start, end, err := d.GetStartAndEndDatesFromRequest(r)
	if err != nil {
		utils.SendErrorResponse(w, err.Error())
		return
	}

	dailySummaries, dates, err := d.GetAllStatisticSummaryInRange(start, end)
	if err != nil {
		utils.SendErrorResponse(w, err.Error())
		return
	}

	format, err := utils.GetPara(r, "format")
	if err != nil {
		format = "json"
	}

	if format == "csv" {
		// Create a buffer to store CSV content
		var csvContent strings.Builder

		// Create a CSV writer
		writer := csv.NewWriter(&csvContent)

		// Write the header row
		header := []string{"Date", "TotalRequest", "ErrorRequest", "ValidRequest", "ForwardTypes", "RequestOrigin", "RequestClientIp", "Referer", "UserAgent", "RequestURL"}
		err := writer.Write(header)
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		// Write each data row
		for i, item := range dailySummaries {
			row := []string{
				dates[i],
				strconv.FormatInt(item.TotalRequest, 10),
				strconv.FormatInt(item.ErrorRequest, 10),
				strconv.FormatInt(item.ValidRequest, 10),
				// Convert map values to a comma-separated string
				strings.Join(mapToStringSlice(item.ForwardTypes), ","),
				strings.Join(mapToStringSlice(item.RequestOrigin), ","),
				strings.Join(mapToStringSlice(item.RequestClientIp), ","),
				strings.Join(mapToStringSlice(item.Referer), ","),
				strings.Join(mapToStringSlice(item.UserAgent), ","),
				strings.Join(mapToStringSlice(item.RequestURL), ","),
			}
			err = writer.Write(row)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		}

		// Flush the CSV writer
		writer.Flush()

		// Check for any errors during writing
		if err := writer.Error(); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		// Set the response headers
		w.Header().Set("Content-Type", "text/csv")
		w.Header().Set("Content-Disposition", "attachment; filename=analytics_"+start+"_to_"+end+".csv")

		// Write the CSV content to the response writer
		_, err = w.Write([]byte(csvContent.String()))
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	} else if format == "json" {
		type exportData struct {
			Stats []*statistic.DailySummaryExport
			Dates []string
		}

		results := exportData{
			Stats: dailySummaries,
			Dates: dates,
		}

		js, _ := json.MarshalIndent(results, "", " ")
		w.Header().Set("Content-Disposition", "attachment; filename=analytics_"+start+"_to_"+end+".json")
		utils.SendJSONResponse(w, string(js))
	} else {
		utils.SendErrorResponse(w, "Unsupported export format")
	}
}

// Reset all the keys within the given time period
func (d *DataLoader) HandleRangeReset(w http.ResponseWriter, r *http.Request) {
	start, end, err := d.GetStartAndEndDatesFromRequest(r)
	if err != nil {
		utils.SendErrorResponse(w, err.Error())
		return
	}

	if r.Method != http.MethodDelete {
		http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
		return
	}

	keys, err := generateDateRange(start, end)
	if err != nil {
		utils.SendErrorResponse(w, err.Error())
		return
	}

	for _, key := range keys {
		log.Println("DELETING statistics " + key)
		d.Database.Delete("stats", key)

		if isTodayDate(key) {
			//It is today's date. Also reset statistic collector value
			log.Println("RESETING today's in-memory statistics")
			d.StatisticCollector.ResetSummaryOfDay()
		}
	}

	utils.SendOK(w)
}
