package web

import (
	"errors"
	"strconv"
	"time"

	"dyproxy/.gen/model"
	"dyproxy/.gen/table"

	"github.com/go-jet/jet/v2/qrm"
	. "github.com/go-jet/jet/v2/sqlite"
	"github.com/gofiber/fiber/v3"
	"github.com/sirupsen/logrus"
)

func (s *WebServer) routeGetFollower(c fiber.Ctx) error {
	if s.pendingItems == nil {
		s.pendingItems = make(map[int32]time.Time)
	}

	tbl := table.Follower

	lastID := c.Query("last", "")
	if lastID != "" {
		id, err := strconv.Atoi(lastID)
		if err != nil {
			return err
		}

		// remove from pending
		s.listLock.Lock()
		delete(s.pendingItems, int32(id))
		s.listLock.Unlock()

		tbl.
			UPDATE(table.Follower.Followed).
			SET(Int32(1)).
			WHERE(table.Follower.ID.EQ(Int32(int32(id)))).
			ExecContext(c.UserContext(), s.db)
	}

	uid := c.Params("uid")

	pendingIDs := []Expression{}
	for i := range s.pendingItems {
		pendingIDs = append(pendingIDs, Int32(i))
	}

	var expert model.Expert
	err := table.Expert.SELECT(table.Expert.State, table.Expert.Since).WHERE(table.Expert.UID.EQ(String(uid))).QueryContext(c.UserContext(), s.db, &expert)
	if err != nil {
		return err
	}

	if expert.State == StateStop {
		return c.JSON(nil)
	}

	condition := tbl.Followed.EQ(Int32(0)).
		AND(tbl.ExpertUID.EQ(String(uid))).
		AND(tbl.ID.NOT_IN(pendingIDs...)).
		AND(tbl.CreatedAt.GT(Int32(expert.Since)))

	stmt := tbl.
		SELECT(tbl.AllColumns).
		WHERE(condition).
		ORDER_BY(table.Follower.ID.DESC()).
		LIMIT(1)
	logrus.Debug(stmt.DebugSql())

	var follower model.Follower
	if err := stmt.QueryContext(c.UserContext(), s.db, &follower); err != nil {
		if errors.Is(err, qrm.ErrNoRows) {
			return c.JSON(nil)
		}
		return err
	}

	s.listLock.Lock()
	s.pendingItems[int32(follower.ID)] = time.Now()
	s.listLock.Unlock()

	return c.JSON(follower)
}

func (s *WebServer) routePostFollower(c fiber.Ctx) error {
	followers := []model.Follower{}
	if err := c.Bind().JSON(&followers); err != nil {
		return err
	}

	tbl := table.Follower

	for _, f := range followers {
		f.CreatedAt = int32(time.Now().In(s.local).Unix())
		_, err := tbl.
			INSERT(tbl.AllColumns.Except(tbl.ID)).
			MODEL(f).
			ON_CONFLICT(tbl.UID).
			DO_NOTHING().
			ExecContext(c.UserContext(), s.db)
		if err != nil {
			logrus.Error(err)
		}
	}

	return nil
}
