package api

import (
	"database/sql"
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"

	"github.com/rycroftapparel/workpulse-api/internal/httpapi"
)

// listCalendarOrg returns calendar events across the organization (superadmin only).
// Query: from, to (required); optional teamId, division (matches reports.division for event owner's reports), userId (filter to one user).
func (s *Server) listCalendarOrg(c *gin.Context) {
	from := c.Query("from")
	to := c.Query("to")
	if from == "" || to == "" {
		c.JSON(http.StatusBadRequest, httpapi.Fail("validation", "from and to query params required (RFC3339 or YYYY-MM-DD)"))
		return
	}

	ctx, cancel := s.ctx(c)
	defer cancel()

	q := `SELECT e.id, e.user_id, e.team_id, e.title, e.starts_at, e.ends_at, e.all_day, e.created_at, e.report_id, e.kind, t.name AS team_name, u.name AS organizer_name
FROM calendar_events e
LEFT JOIN teams t ON t.id = e.team_id
JOIN users u ON u.id = e.user_id
WHERE e.starts_at < $2 AND e.ends_at > $1`
	args := []interface{}{from, to}
	n := 3

	if tidS := strings.TrimSpace(c.Query("teamId")); tidS != "" {
		tid, err := strconv.ParseUint(tidS, 10, 64)
		if err != nil || tid == 0 {
			c.JSON(http.StatusBadRequest, httpapi.Fail("validation", "invalid teamId"))
			return
		}
		q += fmt.Sprintf(" AND e.team_id = $%d", n)
		args = append(args, tid)
		n++
	}
	if div := strings.TrimSpace(c.Query("division")); div != "" {
		q += fmt.Sprintf(` AND EXISTS (
			SELECT 1 FROM reports r WHERE r.user_id = e.user_id
			AND LOWER(TRIM(COALESCE(r.division, ''))) = LOWER(TRIM($%d))
		)`, n)
		args = append(args, div)
		n++
	}
	if uidS := strings.TrimSpace(c.Query("userId")); uidS != "" {
		oid, err := strconv.ParseUint(uidS, 10, 64)
		if err != nil || oid == 0 {
			c.JSON(http.StatusBadRequest, httpapi.Fail("validation", "invalid userId"))
			return
		}
		q += fmt.Sprintf(" AND e.user_id = $%d", n)
		args = append(args, oid)
		n++
	}
	q += ` ORDER BY e.starts_at`

	rows, err := s.DB.QueryContext(ctx, q, args...)
	if err != nil {
		c.JSON(http.StatusInternalServerError, httpapi.Fail("db", err.Error()))
		return
	}
	defer rows.Close()
	out := []gin.H{}
	for rows.Next() {
		var id, rowUserID uint64
		var teamID sql.NullInt64
		var title, organizer string
		var teamName sql.NullString
		var reportID sql.NullInt64
		var kind string
		var start, end time.Time
		var allDay bool
		var created time.Time
		if err := rows.Scan(&id, &rowUserID, &teamID, &title, &start, &end, &allDay, &created, &reportID, &kind, &teamName, &organizer); err != nil {
			c.JSON(http.StatusInternalServerError, httpapi.Fail("db", err.Error()))
			return
		}
		h := gin.H{
			"id": id, "userId": rowUserID, "title": title, "startsAt": start, "endsAt": end,
			"allDay": allDay, "createdAt": created, "organizerName": organizer, "kind": kind,
		}
		if teamID.Valid {
			h["teamId"] = uint64(teamID.Int64)
		}
		if reportID.Valid {
			h["reportId"] = uint64(reportID.Int64)
		}
		if teamName.Valid && strings.TrimSpace(teamName.String) != "" {
			h["teamName"] = teamName.String
		}
		out = append(out, h)
	}
	if err := rows.Err(); err != nil {
		c.JSON(http.StatusInternalServerError, httpapi.Fail("db", err.Error()))
		return
	}
	c.JSON(http.StatusOK, httpapi.OK(out))
}
