package db

import (
	"context"
	"encoding/json"
	"github.com/jackc/pgx/v5/pgtype"
	"lmika.dev/lmika/hugo-cms/gen/sqlc/dbq"
	"lmika.dev/lmika/hugo-cms/models"
	"lmika.dev/pkg/modash/moslice"
	"time"
)

func (db *DB) ListPostsOfSite(ctx context.Context, siteID int64) ([]models.Post, error) {
	res, err := db.q.ListPosts(ctx, siteID)
	if err != nil {
		return nil, err
	}

	return moslice.MapWithError(res, dbPostToPost)
}

func (db *DB) GetPost(ctx context.Context, postID int64) (models.Post, error) {
	res, err := db.q.GetPostWithID(ctx, postID)
	if err != nil {
		return models.Post{}, err
	}

	return dbPostToPost(res)
}

func (db *DB) DeletePost(ctx context.Context, postID int64) error {
	return db.q.DeletePost(ctx, postID)
}

func (db *DB) ListPublishablePosts(ctx context.Context, fromID, siteID int64, now time.Time) ([]models.Post, error) {
	res, err := db.q.ListPublishablePosts(ctx, dbq.ListPublishablePostsParams{
		ID:          fromID,
		SiteID:      siteID,
		PublishDate: pgtype.Timestamptz{Time: now, Valid: true},
	})
	if err != nil {
		return nil, err
	}

	return moslice.MapWithError(res, dbPostToPost)
}

func (db *DB) InsertPost(ctx context.Context, p *models.Post) error {
	props, err := marshalPostProps(p)
	if err != nil {
		return err
	}

	res, err := db.q.InsertPost(ctx, dbq.InsertPostParams{
		SiteID:      p.SiteID,
		Title:       pgtype.Text{String: p.Title, Valid: p.Title != ""},
		Body:        p.Body,
		State:       dbq.PostState(p.State),
		Props:       props,
		PublishDate: pgtype.Timestamptz{Time: p.PublishDate, Valid: !p.PublishDate.IsZero()},
		CreatedAt:   pgtype.Timestamp{Time: p.CreatedAt, Valid: !p.CreatedAt.IsZero()},
		UpdatedAt:   pgtype.Timestamp{Time: p.UpdatedAt, Valid: !p.UpdatedAt.IsZero()},
	})
	if err != nil {
		return err
	}

	p.ID = res
	return nil
}

func (db *DB) UpdatePost(ctx context.Context, p *models.Post) error {
	props, err := marshalPostProps(p)
	if err != nil {
		return err
	}

	return db.q.UpdatePost(ctx, dbq.UpdatePostParams{
		ID:          p.ID,
		SiteID:      p.SiteID,
		Title:       pgtype.Text{String: p.Title, Valid: p.Title != ""},
		Body:        p.Body,
		State:       dbq.PostState(p.State),
		Props:       props,
		PublishDate: pgtype.Timestamptz{Time: p.PublishDate, Valid: !p.PublishDate.IsZero()},
		UpdatedAt:   pgtype.Timestamp{Time: p.UpdatedAt, Valid: !p.UpdatedAt.IsZero()},
	})
}

func marshalPostProps(p *models.Post) ([]byte, error) {
	var props []byte
	if len(p.Params) == 0 {
		props = []byte(`{}`)
	} else {
		var err error
		props, err = json.Marshal(p.Params)
		if err != nil {
			return nil, err
		}
	}
	return props, nil
}
func dbPostToPost(p dbq.Post) (models.Post, error) {
	postProps := map[string]string{}
	if len(p.Props) != 0 {
		if err := json.Unmarshal(p.Props, &postProps); err != nil {
			return models.Post{}, err
		}
	}

	return models.Post{
		ID:          p.ID,
		SiteID:      p.SiteID,
		Title:       p.Title.String,
		Body:        p.Body,
		State:       models.PostState(p.State),
		PublishDate: p.PublishDate.Time,
		CreatedAt:   p.CreatedAt.Time,
	}, nil
}