package database

import (
	"context"
	"fmt"
	"testing"
	"time"

	"git.anthrove.art/Anthrove/otter-space-sdk/v6/pkg/models"
	"git.anthrove.art/Anthrove/otter-space-sdk/v6/test"
	"go.opentelemetry.io/contrib/bridges/otellogrus"
	"go.opentelemetry.io/otel"
	"gorm.io/gorm"
)

func TestCreateScrapeHistory(t *testing.T) {
	// Setup trow away container
	ctx := context.Background()
	container, gormDB, err := test.StartPostgresContainer(ctx)
	if err != nil {
		logger.Fatalf("Could not start PostgreSQL container: %v", err)
	}

	client = gormDB

	// Setup open telemetry
	tracer = otel.Tracer(tracingName)

	hook := otellogrus.NewHook(tracingName)
	logger.AddHook(hook)

	defer container.Terminate(ctx)

	// -- -- Setup Tests

	// -- Create User ot test with
	validUser := models.User{BaseModel: models.BaseModel[models.UserID]{ID: models.UserID(fmt.Sprintf("%025s", "User1"))}}

	validUser, err = CreateUser(ctx, validUser)
	if err != nil {
		t.Fatalf("CreateUser err: %v", err)
	}
	// --

	// -- Create Source to test with
	validSource := models.Source{
		DisplayName: "e621",
		Domain:      "e621.net",
		Icon:        "e621.net/icon.png",
	}

	validSource, err = CreateSource(ctx, validSource)
	if err != nil {
		t.Fatalf("CreateSource err: %v", err)
	}
	// --

	//  -- Create UserSource model
	validUSerSource := models.UserSource{
		BaseModel: models.BaseModel[models.UserSourceID]{
			ID:        models.UserSourceID(fmt.Sprintf("%025s", "UserSourceId1")),
			CreatedAt: time.Now(),
			UpdatedAt: time.Now(),
			DeletedAt: gorm.DeletedAt{},
		},
		User:                 models.User{},
		UserID:               validUser.ID,
		Source:               models.Source{},
		SourceID:             validSource.ID,
		ScrapeTimeInterval:   "P1D",
		AccountUsername:      "marry",
		AccountID:            "poppens",
		LastScrapeTime:       time.Now(),
		AccountValidate:      false,
		AccountValidationKey: "im-a-key",
	}

	validUSerSource, err = CreateUserSource(ctx, validUSerSource)
	if err != nil {
		t.Fatalf("CreateUserSource err: %v", err)
	}

	validScrapeHistory := models.ScrapeHistory{
		ID:           "000000000000valid_task_id",
		UserSourceID: validUSerSource.ID,
	}

	//  --
	tests := []struct {
		name    string
		args    models.ScrapeHistory
		wantErr bool
	}{
		{
			name:    "Valid ScrapeHistory",
			args:    validScrapeHistory,
			wantErr: false,
		},
		{
			name:    "Duplicate ScrapeHistory",
			args:    validScrapeHistory,
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_, err := CreateScrapeHistory(ctx, tt.args)
			if (err != nil) != tt.wantErr {
				t.Errorf("CreateScrapeHistory() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestGetScrapeHistoryByID(t *testing.T) {
	// Setup trow away container
	ctx := context.Background()
	container, gormDB, err := test.StartPostgresContainer(ctx)
	if err != nil {
		logger.Fatalf("Could not start PostgreSQL container: %v", err)
	}

	client = gormDB

	// Setup open telemetry
	tracer = otel.Tracer(tracingName)

	hook := otellogrus.NewHook(tracingName)
	logger.AddHook(hook)

	defer container.Terminate(ctx)

	// -- -- Setup Tests

	// -- Create User ot test with
	validUser := models.User{BaseModel: models.BaseModel[models.UserID]{ID: models.UserID(fmt.Sprintf("%025s", "User1"))}}

	validUser, err = CreateUser(ctx, validUser)
	if err != nil {
		t.Fatalf("CreateUser err: %v", err)
	}
	// --

	// -- Create Source to test with
	validSource := models.Source{
		DisplayName: "e621",
		Domain:      "e621.net",
		Icon:        "e621.net/icon.png",
	}

	validSource, err = CreateSource(ctx, validSource)
	if err != nil {
		t.Fatalf("CreateSource err: %v", err)
	}
	// --

	//  -- Create UserSource model
	validUSerSource := models.UserSource{
		BaseModel: models.BaseModel[models.UserSourceID]{
			ID:        models.UserSourceID(fmt.Sprintf("%025s", "UserSourceId1")),
			CreatedAt: time.Now(),
			UpdatedAt: time.Now(),
			DeletedAt: gorm.DeletedAt{},
		},
		User:                 models.User{},
		UserID:               validUser.ID,
		Source:               models.Source{},
		SourceID:             validSource.ID,
		ScrapeTimeInterval:   "P1D",
		AccountUsername:      "marry",
		AccountID:            "poppens",
		LastScrapeTime:       time.Now(),
		AccountValidate:      false,
		AccountValidationKey: "im-a-key",
	}

	validUSerSource, err = CreateUserSource(ctx, validUSerSource)
	if err != nil {
		t.Fatalf("CreateUserSource err: %v", err)
	}

	validScrapeHistory := models.ScrapeHistory{
		ID:           "000000000000valid_task_id",
		UserSourceID: validUSerSource.ID,
	}

	validScrapeHistory, err = CreateScrapeHistory(ctx, validScrapeHistory)
	if err != nil {
		t.Fatalf("CreateScrapeHistory err: %v", err)
	}

	//  --
	tests := []struct {
		name    string
		id      models.ScrapeTaskID
		wantErr bool
	}{
		{"Valid ID", "000000000000valid_task_id", false},
		{"Empty ID", "", true},
		{"Non-existent ID", "non_existent_id", true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_, err := GetScrapeHistoryByID(ctx, tt.id)
			if (err != nil) != tt.wantErr {
				t.Errorf("GetScrapeHistoryByID() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestUpdateScrapeHistory(t *testing.T) {
	// Setup trow away container
	ctx := context.Background()
	container, gormDB, err := test.StartPostgresContainer(ctx)
	if err != nil {
		logger.Fatalf("Could not start PostgreSQL container: %v", err)
	}

	client = gormDB

	// Setup open telemetry
	tracer = otel.Tracer(tracingName)

	hook := otellogrus.NewHook(tracingName)
	logger.AddHook(hook)

	defer container.Terminate(ctx)

	// -- -- Setup Tests

	// -- Create User ot test with
	validUser := models.User{BaseModel: models.BaseModel[models.UserID]{ID: models.UserID(fmt.Sprintf("%025s", "User1"))}}

	validUser, err = CreateUser(ctx, validUser)
	if err != nil {
		t.Fatalf("CreateUser err: %v", err)
	}
	// --

	// -- Create Source to test with
	validSource := models.Source{
		DisplayName: "e621",
		Domain:      "e621.net",
		Icon:        "e621.net/icon.png",
	}

	validSource, err = CreateSource(ctx, validSource)
	if err != nil {
		t.Fatalf("CreateSource err: %v", err)
	}
	// --

	//  -- Create UserSource model
	validUSerSource := models.UserSource{
		BaseModel: models.BaseModel[models.UserSourceID]{
			ID:        models.UserSourceID(fmt.Sprintf("%025s", "UserSourceId1")),
			CreatedAt: time.Now(),
			UpdatedAt: time.Now(),
			DeletedAt: gorm.DeletedAt{},
		},
		User:                 models.User{},
		UserID:               validUser.ID,
		Source:               models.Source{},
		SourceID:             validSource.ID,
		ScrapeTimeInterval:   "P1D",
		AccountUsername:      "marry",
		AccountID:            "poppens",
		LastScrapeTime:       time.Now(),
		AccountValidate:      false,
		AccountValidationKey: "im-a-key",
	}

	validUSerSource, err = CreateUserSource(ctx, validUSerSource)
	if err != nil {
		t.Fatalf("CreateUserSource err: %v", err)
	}

	validScrapeHistory := models.ScrapeHistory{
		ID:           "000000000000valid_task_id",
		UserSourceID: validUSerSource.ID,
	}

	validScrapeHistory, err = CreateScrapeHistory(ctx, validScrapeHistory)
	if err != nil {
		t.Fatalf("CreateScrapeHistory err: %v", err)
	}

	updatedScrapeHistory := validScrapeHistory
	updatedScrapeHistory.FinishedAt = time.Now()

	//  --

	tests := []struct {
		name    string
		args    models.ScrapeHistory
		wantErr bool
	}{
		{"Valid Update", updatedScrapeHistory, false},
		{"Empty ID", models.ScrapeHistory{ID: ""}, true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := UpdateScrapeHistory(ctx, tt.args)
			if (err != nil) != tt.wantErr {
				t.Errorf("UpdateScrapeHistory() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}

func TestDeleteScrapeHistory(t *testing.T) {
	// Setup trow away container
	ctx := context.Background()
	container, gormDB, err := test.StartPostgresContainer(ctx)
	if err != nil {
		logger.Fatalf("Could not start PostgreSQL container: %v", err)
	}

	client = gormDB

	// Setup open telemetry
	tracer = otel.Tracer(tracingName)

	hook := otellogrus.NewHook(tracingName)
	logger.AddHook(hook)

	defer container.Terminate(ctx)

	// -- -- Setup Tests

	// -- Create User ot test with
	validUser := models.User{BaseModel: models.BaseModel[models.UserID]{ID: models.UserID(fmt.Sprintf("%025s", "User1"))}}

	validUser, err = CreateUser(ctx, validUser)
	if err != nil {
		t.Fatalf("CreateUser err: %v", err)
	}
	// --

	// -- Create Source to test with
	validSource := models.Source{
		DisplayName: "e621",
		Domain:      "e621.net",
		Icon:        "e621.net/icon.png",
	}

	validSource, err = CreateSource(ctx, validSource)
	if err != nil {
		t.Fatalf("CreateSource err: %v", err)
	}
	// --

	//  -- Create UserSource model
	validUSerSource := models.UserSource{
		BaseModel: models.BaseModel[models.UserSourceID]{
			ID:        models.UserSourceID(fmt.Sprintf("%025s", "UserSourceId1")),
			CreatedAt: time.Now(),
			UpdatedAt: time.Now(),
			DeletedAt: gorm.DeletedAt{},
		},
		User:                 models.User{},
		UserID:               validUser.ID,
		Source:               models.Source{},
		SourceID:             validSource.ID,
		ScrapeTimeInterval:   "P1D",
		AccountUsername:      "marry",
		AccountID:            "poppens",
		LastScrapeTime:       time.Now(),
		AccountValidate:      false,
		AccountValidationKey: "im-a-key",
	}

	validUSerSource, err = CreateUserSource(ctx, validUSerSource)
	if err != nil {
		t.Fatalf("CreateUserSource err: %v", err)
	}

	validScrapeHistory := models.ScrapeHistory{
		ID:           "000000000000valid_task_id",
		UserSourceID: validUSerSource.ID,
	}

	validScrapeHistory, err = CreateScrapeHistory(ctx, validScrapeHistory)
	if err != nil {
		t.Fatalf("CreateScrapeHistory err: %v", err)
	}

	//  --
	tests := []struct {
		name    string
		id      models.ScrapeTaskID
		wantErr bool
	}{
		{"Valid ID", "000000000000valid_task_id", false},
		{"Empty ID", "", true},
		{"Short ID", "short_id", true},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := DeleteScrapeHistory(ctx, tt.id)
			if (err != nil) != tt.wantErr {
				t.Errorf("DeleteScrapeHistory() error = %v, wantErr %v", err, tt.wantErr)
			}
		})
	}
}