package models

import (
	"database/sql"
	"time"
)

type Schedule struct {
	ID          int64      `db:"id" json:"id"`
	SyncPairID  int64      `db:"sync_pair_id" json:"sync_pair_id"`
	CronExpr    string     `db:"cron_expr" json:"cron_expr"`
	NextRunAt   *time.Time `db:"next_run_at" json:"next_run_at"`
	Enabled     bool       `db:"enabled" json:"enabled"`
	CreatedAt   time.Time  `db:"created_at" json:"created_at"`
}

type ScheduleRepository struct {
	db *sql.DB
}

func NewScheduleRepository(db *sql.DB) *ScheduleRepository {
	return &ScheduleRepository{db: db}
}

func (r *ScheduleRepository) Create(s *Schedule) (int64, error) {
	res, err := r.db.Exec(`
		INSERT INTO schedules (sync_pair_id, cron_expr, next_run_at, enabled)
		VALUES (?, ?, ?, ?)`,
		s.SyncPairID, s.CronExpr, s.NextRunAt, boolToInt(s.Enabled),
	)
	if err != nil {
		return 0, err
	}
	return res.LastInsertId()
}

func (r *ScheduleRepository) GetAll() ([]Schedule, error) {
	rows, err := r.db.Query(`
		SELECT id, sync_pair_id, cron_expr, next_run_at, enabled, created_at
		FROM schedules ORDER BY id`)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var schedules []Schedule
	for rows.Next() {
		var s Schedule
		var nextRun sql.NullTime
		if err := rows.Scan(&s.ID, &s.SyncPairID, &s.CronExpr, &nextRun,
			&s.Enabled, &s.CreatedAt); err != nil {
			return nil, err
		}
		if nextRun.Valid {
			s.NextRunAt = &nextRun.Time
		}
		s.Enabled = intToBool(intToInt(s.Enabled))
		schedules = append(schedules, s)
	}
	return schedules, rows.Err()
}

func (r *ScheduleRepository) GetByID(id int64) (*Schedule, error) {
	var s Schedule
	var nextRun sql.NullTime
	err := r.db.QueryRow(`
		SELECT id, sync_pair_id, cron_expr, next_run_at, enabled, created_at
		FROM schedules WHERE id = ?`, id).Scan(
		&s.ID, &s.SyncPairID, &s.CronExpr, &nextRun, &s.Enabled, &s.CreatedAt)
	if err != nil {
		return nil, err
	}
	if nextRun.Valid {
		s.NextRunAt = &nextRun.Time
	}
	s.Enabled = intToBool(intToInt(s.Enabled))
	return &s, nil
}

func (r *ScheduleRepository) Update(s *Schedule) error {
	_, err := r.db.Exec(`
		UPDATE schedules SET sync_pair_id=?, cron_expr=?, next_run_at=?, enabled=?
		WHERE id=?`,
		s.SyncPairID, s.CronExpr, s.NextRunAt, boolToInt(s.Enabled), s.ID,
	)
	return err
}

func (r *ScheduleRepository) Delete(id int64) error {
	_, err := r.db.Exec("DELETE FROM schedules WHERE id = ?", id)
	return err
}

func (r *ScheduleRepository) GetEnabledDue(before time.Time) ([]Schedule, error) {
	rows, err := r.db.Query(`
		SELECT id, sync_pair_id, cron_expr, next_run_at, enabled, created_at
		FROM schedules WHERE enabled = 1 AND next_run_at IS NOT NULL AND next_run_at <= ?
		ORDER BY next_run_at`, before)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var schedules []Schedule
	for rows.Next() {
		var s Schedule
		var nextRun sql.NullTime
		if err := rows.Scan(&s.ID, &s.SyncPairID, &s.CronExpr, &nextRun,
			&s.Enabled, &s.CreatedAt); err != nil {
			return nil, err
		}
		if nextRun.Valid {
			s.NextRunAt = &nextRun.Time
		}
		s.Enabled = true
		schedules = append(schedules, s)
	}
	return schedules, rows.Err()
}

func (r *ScheduleRepository) UpdateNextRun(id int64, nextRun time.Time) error {
	_, err := r.db.Exec("UPDATE schedules SET next_run_at = ? WHERE id = ?", nextRun, id)
	return err
}
