package controllers

import (
	"context"
	"encoding/json"
	"nearle/db"
	"nearle/domain"
	"nearle/models"
	"nearle/utils"
	"net/http"
	"strconv"
	"strings"
	"time"

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

func GetActiveRiders(c *fiber.Ctx) error {
	pid, _ := strconv.Atoi(c.Query("partnerid"))
	aid, _ := strconv.Atoi(c.Query("applocationid"))
	uid, _ := strconv.Atoi(c.Query("userid"))
	keyword := c.Query("keyword")

	pageno, _ := strconv.Atoi(c.Query("pageno"))
	pagesize, _ := strconv.Atoi(c.Query("pagesize"))

	result := domain.GetActiveRiders(pid, aid, uid, keyword, pageno, pagesize)

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})
}

func GetActiveRidersv2(c *fiber.Ctx) error {
	pid, _ := strconv.Atoi(c.Query("partnerid"))
	aid, _ := strconv.Atoi(c.Query("applocationid"))
	uid, _ := strconv.Atoi(c.Query("userid"))
	tid, _ := strconv.Atoi(c.Query("tenantid"))

	result := domain.GetActiveRidersv2(pid, aid, uid, tid)

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})
}

func GetRiderShifts(c *fiber.Ctx) error {

	aid, _ := strconv.Atoi(c.Query("applocationid"))

	result := domain.GetRiderShifts(aid)

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})

}

func GetRiderPricing(c *fiber.Ctx) error {

	aid, _ := strconv.Atoi(c.Query("applocationid"))

	result := domain.GetRiderPricing(aid)

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})

}

func GetRiderPool(c *fiber.Ctx) error {

	pid, _ := strconv.Atoi(c.Query("partnerid"))

	result := domain.GetRiderPool(pid)

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})

}

func GetRiderInfo(c *fiber.Ctx) error {

	uid, _ := strconv.Atoi(c.Query("userid"))

	result := domain.GetRiderInfo(uid)

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})

}

func GetRiderInfov2(c *fiber.Ctx) error {

	uid, _ := strconv.Atoi(c.Query("userid"))

	result := domain.GetRiderInfov2(uid)

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})

}

func GetRiderDetails(c *fiber.Ctx) error {

	uid, _ := strconv.Atoi(c.Query("userid"))

	result := domain.GetRiderDetails(uid)

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})

}

func GetAllRiders(c *fiber.Ctx) error {
	aid, _ := strconv.Atoi(c.Query("applocationid"))
	uid, _ := strconv.Atoi(c.Query("userid"))
	pid, _ := strconv.Atoi(c.Query("partnerid"))
	status := c.Query("status")
	keyword := c.Query("keyword")

	pageno, _ := strconv.Atoi(c.Query("pageno"))
	pagesize, _ := strconv.Atoi(c.Query("pagesize"))

	if pageno == 0 {
		pageno = 1
	}

	result := domain.GetAllRiders(aid, pid, uid, status, keyword, pageno, pagesize)

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})
}

func GetPartners(c *fiber.Ctx) error {

	pid, _ := strconv.Atoi(c.Query("user"))
	aid, _ := strconv.Atoi(c.Query("applocationid"))

	result := domain.GetPartners(aid, pid)

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})

}

func GetLocationConfig(c *fiber.Ctx) error {

	uid, _ := strconv.Atoi(c.Query("userid"))
	cid, _ := strconv.Atoi(c.Query("configid"))

	result := domain.GetLocationConfig(uid, cid)

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})

}

func GetPartnerusers(c *fiber.Ctx) error {

	aid, _ := strconv.Atoi(c.Query("applocationid"))

	result := domain.GetPartnerUsers(aid)

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})

}

func GetAdminToken(c *fiber.Ctx) error {
	pid, _ := strconv.Atoi(c.Query("partnerid"))
	tid, _ := strconv.Atoi(c.Query("tenantid"))
	uid, _ := strconv.Atoi(c.Query("userid"))
	aid, _ := strconv.Atoi(c.Query("applocationid"))

	result := domain.GetAdmintoken(pid, uid, tid, aid)

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})
}

func UpdatePartnerUser(c *fiber.Ctx) error {

	var data models.Tenants

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": data,
	})

}

func CreateRider(c *fiber.Ctx) error {

	var data models.Rider

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	err := domain.CreateRider(data)
	if err != nil {

		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err,
			"status":  false,
		})

	} else {

		return c.JSON(fiber.Map{
			"code":    http.StatusCreated,
			"message": "Success",
			"status":  true,
		})

	}

}

func UpdateRiderSettings(c *fiber.Ctx) error {

	var data models.Rider

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	err := domain.UpdateRiderSettings(data)
	if err != nil {

		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err,
			"status":  false,
		})

	} else {

		return c.JSON(fiber.Map{
			"code":    http.StatusCreated,
			"message": "Success",
			"status":  true,
		})

	}

}

func UpdateRiderInfo(c *fiber.Ctx) error {

	var data models.Rider

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	err := domain.UpdateRiderInfo(data)
	if err != nil {

		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err,
			"status":  false,
		})

	} else {

		return c.JSON(fiber.Map{
			"code":    http.StatusCreated,
			"message": "Success",
			"status":  true,
		})

	}

}

func CreateRiderShift(c *fiber.Ctx) error {

	var data models.Ridershifts

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	err := domain.CreateRiderShift(data)
	if err != nil {

		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err,
			"status":  false,
		})

	} else {

		return c.JSON(fiber.Map{
			"code":    http.StatusCreated,
			"message": "Success",
			"status":  true,
		})

	}

}

func CreateRiderLog(c *fiber.Ctx) error {

	var data models.Riderlogs

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	err := domain.CreateRiderLog(data)
	if err != nil {

		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err,
			"status":  false,
		})

	} else {

		return c.JSON(fiber.Map{
			"code":    http.StatusCreated,
			"message": "Success",
			"status":  true,
		})

	}

}

func CreateBreakLog(c *fiber.Ctx) error {

	var data models.Riderbreaks

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	id, err := domain.CreateBreakLog(data)
	if err != nil || id == 0 {

		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err,
			"status":  false,
		})

	}
	data = domain.GetBreaklog(id)

	return c.JSON(fiber.Map{
		"code":    http.StatusCreated,
		"message": "Success",
		"status":  true,
		"details": data,
	})
}

func UpdateBreakLog(c *fiber.Ctx) error {

	var data models.Riderbreaks

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	err := domain.UpdateBreakLog(data)
	if err != nil {

		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err,
			"status":  false,
		})

	} else {

		return c.JSON(fiber.Map{
			"code":    http.StatusAccepted,
			"message": "Success",
			"status":  true,
		})

	}

}

func UpdateRiderLog(c *fiber.Ctx) error {

	var data models.Riderlogs

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	err := domain.UpdateRiderLog(data)
	if err != nil {

		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err,
			"status":  false,
		})

	} else {

		return c.JSON(fiber.Map{
			"code":    http.StatusCreated,
			"message": "Success",
			"status":  true,
		})

	}

}

func GetRiderLog(c *fiber.Ctx) error {

	uid, _ := strconv.Atoi(c.Query("userid"))

	data, err := domain.GetRiderLog(uid)
	if err != nil {

		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err.Error(),
			"status":  false,
		})

	} else {

		return c.JSON(fiber.Map{
			"code":    http.StatusCreated,
			"message": "Success",
			"status":  true,
			"details": data,
		})

	}

}

func GetRiderOrderCount(c *fiber.Ctx) error {

	uid, _ := strconv.Atoi(c.Query("userid"))

	data, err := domain.GetRiderOrderCount(uid)
	if err != nil {

		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err.Error(),
			"status":  false,
		})

	} else {

		return c.JSON(fiber.Map{
			"code":    http.StatusCreated,
			"message": "Success",
			"status":  true,
			"details": data,
		})

	}

}

func GetRiderLogs(c *fiber.Ctx) error {

	pid, _ := strconv.Atoi(c.Query("partnerid"))
	aid, _ := strconv.Atoi(c.Query("applocationid"))
	fdate := c.Query("fromdate")
	tdate := c.Query("todate")
	keyword := c.Query("keyword")

	data := domain.GetRiderLogs(pid, aid, fdate, tdate, keyword)

	return c.JSON(fiber.Map{
		"code":    http.StatusOK,
		"message": "Success",
		"status":  true,
		"details": data,
	})
}

func CreateBreakLogv1(c *fiber.Ctx) error {
	var data models.Riderbreaks
	if err := c.BodyParser(&data); err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": err.Error(),
			"status":  false,
		})
	}

	id, err := domain.CreateBreakLogv1(data)
	if err != nil || id == 0 {
		msg := "Failed to create break log"
		if err != nil {
			msg = err.Error()
		}
		return c.Status(http.StatusConflict).JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": msg,
			"status":  false,
		})
	}

	data = domain.GetBreaklogv1(id)

	return c.Status(http.StatusCreated).JSON(fiber.Map{
		"code":    http.StatusCreated,
		"message": "Success",
		"status":  true,
		"details": data,
	})
}

func UpdateBreakLogv1(c *fiber.Ctx) error {
	var data models.Riderbreaks

	if err := c.BodyParser(&data); err != nil {
		return c.JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Invalid request body",
			"status":  false,
		})
	}

	err := domain.UpdateBreakLogv1(data)
	if err != nil {
		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err.Error(),
			"status":  false,
		})
	}

	return c.JSON(fiber.Map{
		"code":    http.StatusAccepted,
		"message": "Success",
		"status":  true,
	})
}

func GetDeliveryStats(c *fiber.Ctx) error {
	userid := c.Query("userid")
	if userid == "" {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"status":  false,
			"code":    400,
			"message": "Missing userid parameter",
		})
	}

	var stats models.DeliveryStats

	deliveredQuery := `
		SELECT
			SUM(CASE WHEN deliverydate::date = CURRENT_DATE THEN 1 ELSE 0 END) AS today,
			SUM(CASE WHEN EXTRACT(WEEK FROM deliverydate) = EXTRACT(WEEK FROM CURRENT_DATE) AND EXTRACT(YEAR FROM deliverydate) = EXTRACT(YEAR FROM CURRENT_DATE) THEN 1 ELSE 0 END) AS week,
			SUM(CASE WHEN EXTRACT(YEAR FROM deliverydate) = EXTRACT(YEAR FROM CURRENT_DATE) AND EXTRACT(MONTH FROM deliverydate) = EXTRACT(MONTH FROM CURRENT_DATE) THEN 1 ELSE 0 END) AS month,
			COUNT(*) AS total
		FROM deliveries
		WHERE orderstatus = 'delivered' AND userid = ?;
	`

	if err := db.DB.Raw(deliveredQuery, userid).Scan(&stats).Error; err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"status":  false,
			"code":    500,
			"message": "Failed to fetch delivered stats",
		})
	}

	cancelledQuery := `
		SELECT
			COALESCE(SUM(CASE WHEN orderstatus = 'cancelled' THEN 1 ELSE 0 END), 0) AS cancelled
		FROM deliveries
		WHERE userid = ?;
	`

	if err := db.DB.Raw(cancelledQuery, userid).Scan(&stats.Cancelled).Error; err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"status":  false,
			"code":    500,
			"message": "Failed to fetch cancelled stats",
		})
	}

	return c.JSON(fiber.Map{
		"code":    200,
		"status":  true,
		"message": "Delivery stats fetched successfully",
		"data":    stats,
	})
}

func GetRiderWeeklyKms(c *fiber.Ctx) error {
	uidStr := c.Query("userid")
	if uidStr == "" {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    400,
			"message": "Missing userid parameter",
			"status":  false,
		})
	}

	uid, err := strconv.Atoi(uidStr)
	if err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    400,
			"message": "Invalid userid",
			"status":  false,
		})
	}

	data, err := domain.GetRiderWeeklyKms(uid)
	if err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    500,
			"message": "Failed to fetch rider kms",
			"status":  false,
			"error":   err.Error(),
		})
	}

	return c.JSON(fiber.Map{
		"code":        http.StatusOK,
		"message":     "Rider kms fetched successfully",
		"status":      true,
		"total_kms":   data.TotalKms,
		"overall_kms": data.OverallKms,
		"details":     data.Details,
	})
}

func CreateRiderLogv1(c *fiber.Ctx) error {
	var data models.Riderlogs

	if err := c.BodyParser(&data); err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Invalid request body",
			"status":  false,
		})
	}

	err := domain.CreateRiderLogv1(data)
	if err != nil {
		return c.Status(http.StatusConflict).JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err.Error(),
			"status":  false,
		})
	}

	return c.Status(http.StatusCreated).JSON(fiber.Map{
		"code":    http.StatusCreated,
		"message": "Success",
		"status":  true,
	})
}

func UpdateRiderLogv1(c *fiber.Ctx) error {
	var data models.Riderlogs

	if err := c.BodyParser(&data); err != nil {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "Invalid request body",
			"status":  false,
		})
	}

	err := domain.UpdateRiderLogv1(data)
	if err != nil {
		return c.Status(http.StatusConflict).JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err.Error(),
			"status":  false,
		})
	}

	return c.Status(http.StatusCreated).JSON(fiber.Map{
		"code":    http.StatusCreated,
		"message": "Success",
		"status":  true,
	})
}

func CreateRiderSupport(c *fiber.Ctx) error {

	var data models.RiderSupport

	if err := c.BodyParser(&data); err != nil {
		return err
	}

	err := domain.CreateRiderSupport(data)
	if err != nil {
		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err,
			"status":  false,
		})
	} else {
		return c.JSON(fiber.Map{
			"code":    http.StatusCreated,
			"message": "Success",
			"status":  true,
		})
	}
}

func GetRiderSupport(c *fiber.Ctx) error {

	uid, _ := strconv.Atoi(c.Query("userid"))

	data, err := domain.GetRiderSupport(uid)
	if err != nil {
		return c.JSON(fiber.Map{
			"code":    http.StatusConflict,
			"message": err,
			"status":  false,
		})
	} else {
		return c.JSON(fiber.Map{
			"code":    http.StatusOK,
			"message": "Success",
			"status":  true,
			"data":    data,
		})
	}
}

func GetRiderLogsv1(c *fiber.Ctx) error {
	fromdate := c.Query("fromdate")
	todate := c.Query("todate")
	keyword := c.Query("keyword")

	partneridStr := c.Query("partnerid")
	partnerid, _ := strconv.Atoi(partneridStr)

	if fromdate == "" || todate == "" {
		return c.Status(http.StatusBadRequest).JSON(fiber.Map{
			"code":    http.StatusBadRequest,
			"message": "fromdate and todate are required",
			"status":  false,
		})
	}

	logs, err := domain.GetRiderLogsv1(fromdate, todate, keyword, partnerid)
	if err != nil {
		return c.Status(http.StatusInternalServerError).JSON(fiber.Map{
			"code":    http.StatusInternalServerError,
			"message": err.Error(),
			"status":  false,
		})
	}

	return c.JSON(fiber.Map{
		"code":    200,
		"details": logs,
		"status":  true,
	})
}

func DeleteRiderLogs(c *fiber.Ctx) error {
	useridStr := c.Query("userid")
	fromStr := c.Query("fromdate")
	toStr := c.Query("todate")

	if useridStr == "" || fromStr == "" || toStr == "" {
		return c.Status(400).JSON(fiber.Map{
			"status":  false,
			"code":    400,
			"message": "userid, fromdate and todate are required",
		})
	}

	userid, _ := strconv.Atoi(useridStr)

	layout := "2006-01-02"
	fromDate, err := time.Parse(layout, fromStr)
	if err != nil {
		return c.Status(400).JSON(fiber.Map{
			"status":  false,
			"code":    400,
			"message": "Invalid fromdate format (YYYY-MM-DD)",
		})
	}

	toDate, err := time.Parse(layout, toStr)
	if err != nil {
		return c.Status(400).JSON(fiber.Map{
			"status":  false,
			"code":    400,
			"message": "Invalid todate format (YYYY-MM-DD)",
		})
	}

	ctx := context.Background()

	logs, err := db.Rdb.LRange(ctx, "riderlogs", 0, -1).Result()
	if err != nil {
		return c.Status(500).JSON(fiber.Map{
			"status":  false,
			"code":    500,
			"message": "Failed to read riderlogs from Redis",
		})
	}

	db.Rdb.Del(ctx, "riderlogs")

	deletedCount := 0

	for _, item := range logs {
		var log models.Deliverylogs
		json.Unmarshal([]byte(item), &log)

		logDate, err := time.Parse("2006-01-02", log.Logdate)
		if err != nil {
			continue
		}

		if log.Userid == userid && (logDate.Equal(fromDate) || logDate.After(fromDate)) &&
			(logDate.Equal(toDate) || logDate.Before(toDate)) {

			deletedCount++
			continue
		}

		db.Rdb.RPush(ctx, "riderlogs", item)
	}

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    200,
		"message": "Filtered rider logs deleted successfully",
		"deleted": deletedCount,
	})
}

func GetAllRidersSummary(c *fiber.Ctx) error {
	aid, _ := strconv.Atoi(c.Query("applocationid"))
	uid, _ := strconv.Atoi(c.Query("userid"))
	pid, _ := strconv.Atoi(c.Query("partnerid"))
	keyword := c.Query("keyword")

	result := domain.GetAllRidersSummary(aid, pid, uid, keyword)

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})
}

func GetActiveRidersSummary(c *fiber.Ctx) error {
	pid, _ := strconv.Atoi(c.Query("partnerid"))
	aid, _ := strconv.Atoi(c.Query("applocationid"))
	uid, _ := strconv.Atoi(c.Query("userid"))
	keyword := c.Query("keyword")

	result := domain.GetActiveRidersSummary(pid, aid, uid, keyword)

	return c.JSON(fiber.Map{
		"status":  true,
		"code":    http.StatusOK,
		"message": "Successful",
		"details": result,
	})
}

func GetUserLocationSummary(c *fiber.Ctx) error {

	aid, _ := strconv.Atoi(c.Query("applocationid"))
	pid, _ := strconv.Atoi(c.Query("partnerid"))
	tid, _ := strconv.Atoi(c.Query("tenantid"))
	lid, _ := strconv.Atoi(c.Query("locationid"))
	uid, _ := strconv.Atoi(c.Query("userid"))
	fdate := c.Query("fromdate")
	tdate := c.Query("todate")

	var data []models.UserReportSummary
	var where []string
	var args []interface{}

	where = append(where, "a.configid = 6")

	if fdate != "" && tdate != "" {
		where = append(where, "b.deliverydate::date BETWEEN ?::date AND ?::date")
		args = append(args, fdate, tdate)
	}

	if tid != 0 {
		where = append(where, "b.tenantid = ?")
		args = append(args, tid)
	}

	if lid != 0 {
		where = append(where, "b.locationid = ?")
		args = append(args, lid)
	}

	if aid != 0 {
		where = append(where, "a.applocationid = ?")
		args = append(args, aid)
	}

	if pid != 0 {
		where = append(where, "a.partnerid = ?")
		args = append(args, pid)
	}

	if uid != 0 {
		where = append(where, "a.userid = ?")
		args = append(args, uid)
	}

	q := Ridersummary

	if len(where) > 0 {
		q += " WHERE " + strings.Join(where, " AND ")
	}

	q += `
	GROUP BY
		a.userid,
		b.locationid
	ORDER BY
		a.userid
	`

	utils.Logger.Debugw("RiderSummary SQL generated", "query", q)

	if err := db.DB.Raw(q, args...).Scan(&data).Error; err != nil {
		return c.Status(500).JSON(fiber.Map{
			"code":    500,
			"status":  false,
			"message": err.Error(),
		})
	}

	return c.JSON(fiber.Map{
		"code":    200,
		"message": "Success",
		"status":  true,
		"details": data,
	})
}
