package services_test

import (
	"context"
	"regexp"
	"testing"
	"time"

	"github.com/DATA-DOG/go-sqlmock"
	"github.com/rede5/gohorsejobs/backend/internal/services"
	"github.com/stretchr/testify/assert"
)

func TestTicketService_CRUD(t *testing.T) {
	db, mock, err := sqlmock.New()
	assert.NoError(t, err)
	defer db.Close()

	service := services.NewTicketService(db)
	ctx := context.Background()

	// 1. Create Ticket
	mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO tickets`)).
		WithArgs("user-id", "Help", "high").
		WillReturnRows(sqlmock.NewRows([]string{"id", "user_id", "subject", "status", "priority", "created_at", "updated_at"}).
			AddRow("ticket-id", "user-id", "Help", "open", "high", time.Now(), time.Now()))

	ticket, err := service.CreateTicket(ctx, "user-id", "Help", "high")
	assert.NoError(t, err)
	assert.Equal(t, "ticket-id", ticket.ID)

	// 2. List Tickets
	mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, user_id, subject, status, priority, created_at, updated_at FROM tickets`)).
		WithArgs("user-id").
		WillReturnRows(sqlmock.NewRows([]string{"id", "user_id", "subject", "status", "priority", "created_at", "updated_at"}).
			AddRow("ticket-id", "user-id", "Help", "open", "high", time.Now(), time.Now()))

	tickets, err := service.ListTickets(ctx, "user-id")
	assert.NoError(t, err)
	assert.Equal(t, 1, len(tickets))

	// 3. Add Message
	mock.ExpectQuery(regexp.QuoteMeta(`SELECT COUNT(*) FROM tickets`)).
		WithArgs("ticket-id", "user-id").
		WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))

	mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO ticket_messages`)).
		WithArgs("ticket-id", "user-id", "reply").
		WillReturnRows(sqlmock.NewRows([]string{"id", "ticket_id", "user_id", "message", "created_at"}).
			AddRow("msg-id", "ticket-id", "user-id", "reply", time.Now()))

	mock.ExpectExec(regexp.QuoteMeta(`UPDATE tickets SET updated_at`)).
		WithArgs("ticket-id").
		WillReturnResult(sqlmock.NewResult(1, 1))

	msg, err := service.AddMessage(ctx, "ticket-id", "user-id", "reply", false)
	assert.NoError(t, err)
	assert.NotNil(t, msg)

	// 4. Close Ticket
	mock.ExpectQuery(regexp.QuoteMeta(`SELECT user_id FROM tickets WHERE id = $1`)).
		WithArgs("ticket-id").
		WillReturnRows(sqlmock.NewRows([]string{"user_id"}).AddRow("user-id"))

	mock.ExpectQuery(regexp.QuoteMeta(`UPDATE tickets SET updated_at = NOW(), status = $1 WHERE id = $2`)).
		WillReturnRows(sqlmock.NewRows([]string{"id", "user_id", "subject", "status", "priority", "created_at", "updated_at"}).
			AddRow("ticket-id", "user-id", "Help", "closed", "high", time.Now(), time.Now()))

	_, err = service.CloseTicket(ctx, "ticket-id", "user-id", false)
	assert.NoError(t, err)
}

func TestTicketService_Extended(t *testing.T) {
	db, mock, err := sqlmock.New()
	assert.NoError(t, err)
	defer db.Close()

	service := services.NewTicketService(db)
	ctx := context.Background()

	// 1. GetTicket (With messages)
	mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, user_id, subject, status, priority, created_at, updated_at FROM tickets WHERE id = $1 AND user_id = $2`)).
		WithArgs("ticket-id", "user-id").
		WillReturnRows(sqlmock.NewRows([]string{"id", "user_id", "subject", "status", "priority", "created_at", "updated_at"}).
			AddRow("ticket-id", "user-id", "Subject", "open", "high", time.Now(), time.Now()))

	mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, ticket_id, user_id, message, created_at FROM ticket_messages WHERE ticket_id = $1 ORDER BY created_at ASC`)).
		WithArgs("ticket-id").
		WillReturnRows(sqlmock.NewRows([]string{"id", "ticket_id", "user_id", "message", "created_at"}).
			AddRow("msg-1", "ticket-id", "user-id", "msg body", time.Now()))

	tTicket, tMsgs, err := service.GetTicket(ctx, "ticket-id", "user-id", false)
	assert.NoError(t, err)
	assert.Equal(t, "ticket-id", tTicket.ID)
	assert.Len(t, tMsgs, 1)

	// 2. DeleteTicket
	mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM ticket_messages WHERE ticket_id = $1`)).
		WithArgs("ticket-id").
		WillReturnResult(sqlmock.NewResult(0, 1))

	mock.ExpectExec(regexp.QuoteMeta(`DELETE FROM tickets WHERE id = $1`)).
		WithArgs("ticket-id").
		WillReturnResult(sqlmock.NewResult(0, 1))

	err = service.DeleteTicket(ctx, "ticket-id")
	assert.NoError(t, err)

	// 3. ListAllTickets
	mock.ExpectQuery(regexp.QuoteMeta(`SELECT id, user_id, subject, status, priority, created_at, updated_at FROM tickets ORDER BY updated_at DESC`)).
		WillReturnRows(sqlmock.NewRows([]string{"id", "user_id", "subject", "status", "priority", "created_at", "updated_at"}).
			AddRow("ticket-1", "u1", "s1", "open", "low", time.Now(), time.Now()).
			AddRow("ticket-2", "u2", "s2", "closed", "high", time.Now(), time.Now()))

	allTickets, err := service.ListAllTickets(ctx, "")
	assert.NoError(t, err)
	assert.Len(t, allTickets, 2)
}
