package dailyreport

import (
	"encoding/json"
	"errors"
	"fmt"
	"strings"
	"system-altrak/pkg/utils"
	"time"

	"github.com/gofiber/fiber/v2"
	"gorm.io/gorm"
)

type Handler struct {
	service DailyReportService
}

func parseCustomerNamesParam(raw string) []string {
	raw = strings.TrimSpace(raw)
	if raw == "" {
		return nil
	}

	var names []string
	if err := json.Unmarshal([]byte(raw), &names); err == nil {
		return normalizeCustomerNames(names)
	}

	parts := strings.Split(raw, ",")
	return normalizeCustomerNames(parts)
}

func normalizeCustomerNames(values []string) []string {
	result := make([]string, 0, len(values))
	seen := map[string]struct{}{}
	for _, value := range values {
		name := strings.TrimSpace(value)
		if name == "" {
			continue
		}
		key := strings.ToLower(name)
		if _, ok := seen[key]; ok {
			continue
		}
		seen[key] = struct{}{}
		result = append(result, name)
	}
	return result
}

func NewHandler(s DailyReportService) *Handler {
	return &Handler{service: s}
}

func (h *Handler) ListHistoricalArchive(c *fiber.Ctx) error {
	branchID, _ := c.Locals("current_branch_id").(uint)
	role, _ := c.Locals("role").(string)
	search := c.Query("search", "")
	from := c.Query("from_verify", "")
	to := c.Query("to_verify", "")
	list, err := h.service.FetchHistoricalRecords(search, from, to, branchID, role)
	if err != nil {
		return utils.InternalErrorResponse(c, "Failed to aggregate historical documentation archives")
	}
	return utils.SuccessResponse(c, "Historical archive synchronized successfully", list)
}

func (h *Handler) RevertVerification(c *fiber.Ctx) error {
	id, err := utils.ParseParamID(c, "id")
	if err != nil {
		return utils.ErrorResponse(c, fiber.StatusBadRequest, "Invalid ID parameter")
	}
	branchID, _ := c.Locals("current_branch_id").(uint)
	role, _ := c.Locals("role").(string)
	if err := h.service.RevertVerification(id, branchID, role); err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return utils.NotFoundResponse(c, "Operational Record")
		}
		return utils.InternalErrorResponse(c, err.Error())
	}
	return utils.SuccessResponse(c, "Operational verification successfully reverted to pending state", nil)
}

// MarkExported marks the given record IDs as exported and stores the export timestamp.
// After this, records will no longer appear in the active Daily Report table.
func (h *Handler) MarkExported(c *fiber.Ctx) error {
	var body struct {
		IDs []uint `json:"ids"`
	}
	if err := c.BodyParser(&body); err != nil || len(body.IDs) == 0 {
		return utils.ErrorResponse(c, fiber.StatusBadRequest, "Invalid or empty ID list")
	}

	branchID, _ := c.Locals("current_branch_id").(uint)
	userID, _ := c.Locals("user_id").(uint)

	if err := h.service.MarkAsExported(body.IDs, branchID, userID); err != nil {
		return utils.InternalErrorResponse(c, "Failed to mark records as exported")
	}

	return utils.SuccessResponse(c, "Records successfully archived as exported", map[string]interface{}{
		"count":       len(body.IDs),
		"exported_by": userID,
	})
}

func (h *Handler) ExportExcel(c *fiber.Ctx) error {
	branchID, _ := c.Locals("current_branch_id").(uint)
	role, _ := c.Locals("role").(string)
	search := c.Query("search", "")
	from := c.Query("from_verify", "")
	to := c.Query("to_verify", "")
	cutoff := c.Query("cutoff", "")
	customerMode := c.Query("customer_mode", "all")
	customerNames := parseCustomerNamesParam(c.Query("customers", ""))

	sortMode := c.Query("sort", "time")
	buf, err := h.service.ExportExcel(search, from, to, cutoff, customerMode, customerNames, branchID, role, sortMode)
	if err != nil {
		return utils.InternalErrorResponse(c, "Failed to compile dataset")
	}

	c.Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
	c.Set("Content-Disposition", `attachment; filename="Daily-Verified-Report.xlsx"`)
	return c.Send(buf)
}

func (h *Handler) servePdf(c *fiber.Ctx, contentDisposition string) error {
	branchID, _ := c.Locals("current_branch_id").(uint)
	role, _ := c.Locals("role").(string)
	search := c.Query("search", "")
	from := c.Query("from_verify", "")
	to := c.Query("to_verify", "")
	cutoff := c.Query("cutoff", "")
	customerMode := c.Query("customer_mode", "all")
	customerNames := parseCustomerNamesParam(c.Query("customers", ""))

	sortMode := c.Query("sort", "time")
	buf, err := h.service.ExportPdf(search, from, to, cutoff, customerMode, customerNames, branchID, role, sortMode)
	if err != nil {
		return utils.InternalErrorResponse(c, "Failed to compile visual dataset")
	}

	c.Set("Content-Type", "application/pdf")
	c.Set("Content-Disposition", contentDisposition)
	return c.Send(buf)
}

func (h *Handler) ExportPdf(c *fiber.Ctx) error {
	return h.servePdf(c, `attachment; filename="Daily-Verified-Report.pdf"`)
}

func (h *Handler) PreviewPdf(c *fiber.Ctx) error {
	return h.servePdf(c, `inline; filename="Daily-Verified-Report.pdf"`)
}

func (h *Handler) GetLastArchivedAt(c *fiber.Ctx) error {
	branchID, _ := c.Locals("current_branch_id").(uint)
	last, err := h.service.GetLastArchivedAt(branchID)
	if err != nil {
		return utils.InternalErrorResponse(c, "Failed to retrieve last archival metadata")
	}
	if last == nil {
		return utils.SuccessResponse(c, "No archival records found", nil)
	}
	return utils.SuccessResponse(c, "Success", map[string]interface{}{
		"last_archived_at": last,
		"formatted":       last.Format("02/01/2006 15:04"),
	})
}

func (h *Handler) GetYearlySummary(c *fiber.Ctx) error {
	branchID, _ := c.Locals("current_branch_id").(uint)
	year := c.QueryInt("year", time.Now().Year())
	
	buf, err := h.service.GetYearlySummary(year, branchID)
	if err != nil {
		return utils.ErrorResponse(c, fiber.StatusNotFound, err.Error())
	}

	c.Set("Content-Type", "application/pdf")
	c.Set("Content-Disposition", fmt.Sprintf(`attachment; filename="Yearly-Summary-%d.pdf"`, year))
	return c.Send(buf)
}
