package repositories

import (
	"context"
	"database/sql"
	"strings"

	"gitea.d3m0k1d.ru/d3m0k1d/d3m0k1d.ru/backend/internal/logger"
	"gitea.d3m0k1d.ru/d3m0k1d/d3m0k1d.ru/backend/internal/storage"
)

type postRepository struct {
	db     *sql.DB
	logger *logger.Logger
}

func NewPostRepository(db *sql.DB) PostRepository {
	return &postRepository{
		db:     db,
		logger: logger.New(false),
	}
}
func (p *postRepository) GetAll(ctx context.Context) ([]storage.PostReq, error) {
	var result []storage.PostReq
	rows, err := p.db.Query("SELECT id, title, content, CREATED_AT FROM posts WHERE published = 1")
	if err != nil {
		p.logger.Error(err.Error())
		return nil, err
	}
	for rows.Next() {
		var title string
		var content string
		var id int
		var createdAt string
		err := rows.Scan(&id, &title, &content, &createdAt)
		if err != nil {
			p.logger.Error("error scan: " + err.Error())
		}
		result = append(result, storage.PostReq{
			ID:        id,
			Title:     title,
			Content:   content,
			CreatedAt: createdAt,
		})
	}
	return result, nil
}

func (p *postRepository) GetByID(ctx context.Context, id int) (storage.PostReq, error) {
	var result storage.PostReq
	row := p.db.QueryRow(
		"SELECT title, content, CREATED_AT FROM posts WHERE id = ? AND published = 1",
		id,
	)
	var title string
	var content string
	var createdAt string
	err := row.Scan(&title, &content, &createdAt)
	if err != nil {
		p.logger.Error("error scan: " + err.Error())
	}
	result = storage.PostReq{
		ID:        id,
		Title:     title,
		Content:   content,
		CreatedAt: createdAt,
	}
	return result, nil
}

func (p *postRepository) Create(ctx context.Context, post storage.Post) error {
	query, err := p.db.Exec(
		"INSERT INTO posts(title, content) VALUES(?, ?, ?)",
		post.Title,
		post.Content,
		post.Tags,
	)
	if err != nil {
		return err
	}
	id, err := query.LastInsertId()
	if err != nil {
		return err
	}
	p.logger.Info("Post created:", "id", id)
	return nil
}

func (p *postRepository) Update(ctx context.Context, id int, post storage.Post) error {
	query := "UPDATE posts SET "
	args := []interface{}{}
	updates := []string{}

	if post.Title != "" {
		updates = append(updates, "title = ?")
		args = append(args, post.Title)
	}
	if post.Tags != "" {
		updates = append(updates, "tags = ?")
		args = append(args, post.Tags)
	}
	if post.Content != "" {
		updates = append(updates, "content = ?")
		args = append(args, post.Content)
	}

	updates = append(updates, "published = ?")
	args = append(args, post.Published)
	updates = append(updates, "updated_at = CURRENT_TIMESTAMP")
	query += strings.Join(updates, ", ")
	query += " WHERE id = ?"
	args = append(args, id)

	_, err := p.db.ExecContext(ctx, query, args...)
	return err
}

func (p *postRepository) Delete(ctx context.Context, id int) error {
	_, err := p.db.Exec("DELETE FROM posts WHERE id = ?", id)
	if err != nil {
		return err
	}
	p.logger.Info("Post deleted:", "id", id)
	return nil
}

func (p *postRepository) GetLastID(ctx context.Context) (int, error) {
	var id int
	row := p.db.QueryRow("SELECT id FROM posts ORDER BY id DESC LIMIT 1")
	err := row.Scan(&id)
	if err != nil {
		p.logger.Error("error scan: " + err.Error())
	}
	return id, nil
}

func (p *postRepository) IsExist(ctx context.Context, id int) bool {
	var exists int
	err := p.db.QueryRowContext(ctx, "SELECT 1 FROM posts WHERE id = ? LIMIT 1", id).Scan(&exists)
	if err != nil {
		if err == sql.ErrNoRows {
			return false
		}
		p.logger.Error("error checking post existence: " + err.Error())
		return false
	}
	return true
}

func (p *postRepository) GetAllAdmin(ctx context.Context) ([]storage.PostReq, error) {
	result := []storage.PostReq{}
	rows, err := p.db.Query("SELECT id, title, content, tags, CREATED_AT FROM posts")
	if err != nil {
		p.logger.Error(err.Error())
		return nil, err
	}
	for rows.Next() {
		var title string
		var content string
		var id int
		var tags string
		var createdAt string
		err := rows.Scan(&id, &title, &content, &tags, &createdAt)
		if err != nil {
			p.logger.Error("error scan: " + err.Error())
		}
		result = append(result, storage.PostReq{
			ID:        id,
			Title:     title,
			Content:   content,
			Tags:      tags,
			CreatedAt: createdAt,
		})
	}
	return result, nil
}
