package backend

import (
	"fmt"
	"log"
)

func (db *DB) WriteArticleContributors(articleID int64, contributorIDs []int64) error {
	query := "INSERT INTO articles_contributors (article_id, contributor_id) VALUES (?, ?)"

	for i := 0; i < TxMaxRetries; i++ {
		err := func() error {
			tx, err := db.Begin()
			if err != nil {
				return fmt.Errorf("error starting transaction: %v", err)
			}

			for _, contributorID := range contributorIDs {
				if _, err := tx.Exec(query, articleID, contributorID); err != nil {
					if rollbackErr := tx.Rollback(); rollbackErr != nil {
						log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
					}
					return fmt.Errorf("error inserting into articles_contributors: %v", err)
				}
			}

			if err = tx.Commit(); err != nil {
				return fmt.Errorf("error committing transaction: %v", err)
			}
			return nil
		}()
		if err == nil {
			return nil
		}

		log.Println(err)
		wait(i)
	}
	return fmt.Errorf("error: %v unsuccessful retries for DB operation, aborting", TxMaxRetries)
}

func (db *DB) GetArticleContributors(c *Config, articleID int64) ([]*User, error) {
	query := `
    SELECT u.id
    FROM articles a
        INNER JOIN articles_contributors ac ON a.id = ac.article_id
        INNER JOIN users u ON ac.contributor_id = u.id
    WHERE a.id = ?
    `
	rows, err := db.Query(query, articleID)
	if err != nil {
		return nil, fmt.Errorf("error querying articles_contributors: %v", err)
	}

	contributors := make([]*User, 0)
	for rows.Next() {
		var contributorID int64

		if err = rows.Scan(&contributorID); err != nil {
			return nil, fmt.Errorf("error scanning rows: %v", err)
		}

		contributor, err := db.GetUser(c, contributorID)
		if err != nil {
			return nil, fmt.Errorf("error getting user info for article contributor: %v", err)
		}

		contributors = append(contributors, contributor)
	}

	return contributors, nil
}

func (db *DB) UpdateArticleContributors(articleID int64, contributorIDs []int64) error {
	deleteQuery := "DELETE FROM articles_contributors WHERE article_id = ?"
	insertQuery := "INSERT INTO articles_contributors (article_id, contributor_id) VALUES (?, ?)"

	for i := 0; i < TxMaxRetries; i++ {
		err := func() error {
			tx, err := db.Begin()
			if err != nil {
				return fmt.Errorf("error starting transaction: %v", err)
			}

			if _, err := tx.Exec(deleteQuery, articleID); err != nil {
				if rollbackErr := tx.Rollback(); rollbackErr != nil {
					log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
				}
				return fmt.Errorf("error deleting entries from articles_contributors before inserting new ones: %v", err)
			}

			for _, contributorID := range contributorIDs {
				if _, err := tx.Exec(insertQuery, articleID, contributorID); err != nil {
					if rollbackErr := tx.Rollback(); rollbackErr != nil {
						log.Fatalf("transaction error: %v, rollback error: %v", err, rollbackErr)
					}
					return fmt.Errorf("error inserting new entries into articles_contributors: %v", err)
				}
			}

			if err = tx.Commit(); err != nil {
				return fmt.Errorf("error committing transaction: %v", err)
			}
			return nil
		}()
		if err == nil {
			return nil
		}

		log.Println(err)
		wait(i)
	}
	return fmt.Errorf("error: %v unsuccessful retries for DB operation, aborting", TxMaxRetries)
}

func (db *DB) DeleteArticleContributors(articleID int64) error {
	query := "DELETE FROM articles_contributors WHERE article_id = ?"

	_, err := db.Exec(query, articleID)
	if err != nil {
		return fmt.Errorf("error deleting articles_contributors %v from DB: %v", articleID, err)
	}

	return nil
}