package engine

import (
	"context"
	"database/sql"
	"fmt"

	"github.com/insertr/insertr/internal/db"
	"github.com/insertr/insertr/internal/db/postgresql"
	"github.com/insertr/insertr/internal/db/sqlite"
)

// Helper function to convert sql.NullString to string
func getStringFromNullString(ns sql.NullString) string {
	if ns.Valid {
		return ns.String
	}
	return ""
}

// DatabaseClient implements ContentClient interface using the database
type DatabaseClient struct {
	database *db.Database
}

// NewDatabaseClient creates a new database client
func NewDatabaseClient(database *db.Database) *DatabaseClient {
	return &DatabaseClient{
		database: database,
	}
}

// GetContent retrieves a single content item
func (c *DatabaseClient) GetContent(siteID, contentID string) (*ContentItem, error) {
	switch c.database.GetDBType() {
	case "sqlite3":
		content, err := c.database.GetSQLiteQueries().GetContent(context.Background(), sqlite.GetContentParams{
			ID:     contentID,
			SiteID: siteID,
		})
		if err != nil {
			return nil, err
		}
		return &ContentItem{
			ID:               content.ID,
			SiteID:           content.SiteID,
			HTMLContent:      content.HtmlContent,
			OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
			LastEditedBy:     content.LastEditedBy,
		}, nil

	case "postgresql":
		content, err := c.database.GetPostgreSQLQueries().GetContent(context.Background(), postgresql.GetContentParams{
			ID:     contentID,
			SiteID: siteID,
		})
		if err != nil {
			return nil, err
		}
		return &ContentItem{
			ID:               content.ID,
			SiteID:           content.SiteID,
			HTMLContent:      content.HtmlContent,
			OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
			LastEditedBy:     content.LastEditedBy,
		}, nil

	default:
		return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
	}
}

// GetBulkContent retrieves multiple content items
func (c *DatabaseClient) GetBulkContent(siteID string, contentIDs []string) (map[string]ContentItem, error) {
	switch c.database.GetDBType() {
	case "sqlite3":
		contents, err := c.database.GetSQLiteQueries().GetBulkContent(context.Background(), sqlite.GetBulkContentParams{
			SiteID: siteID,
			Ids:    contentIDs,
		})
		if err != nil {
			return nil, err
		}

		items := make(map[string]ContentItem)
		for _, content := range contents {
			items[content.ID] = ContentItem{
				ID:               content.ID,
				SiteID:           content.SiteID,
				HTMLContent:      content.HtmlContent,
				OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
				LastEditedBy:     content.LastEditedBy,
			}
		}
		return items, nil

	case "postgresql":
		contents, err := c.database.GetPostgreSQLQueries().GetBulkContent(context.Background(), postgresql.GetBulkContentParams{
			SiteID: siteID,
			Ids:    contentIDs,
		})
		if err != nil {
			return nil, err
		}

		items := make(map[string]ContentItem)
		for _, content := range contents {
			items[content.ID] = ContentItem{
				ID:               content.ID,
				SiteID:           content.SiteID,
				HTMLContent:      content.HtmlContent,
				OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
				LastEditedBy:     content.LastEditedBy,
			}
		}
		return items, nil

	default:
		return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
	}
}

// GetAllContent retrieves all content items for a site
func (c *DatabaseClient) GetAllContent(siteID string) (map[string]ContentItem, error) {
	switch c.database.GetDBType() {
	case "sqlite3":
		contents, err := c.database.GetSQLiteQueries().GetAllContent(context.Background(), siteID)
		if err != nil {
			return nil, err
		}

		items := make(map[string]ContentItem)
		for _, content := range contents {
			items[content.ID] = ContentItem{
				ID:               content.ID,
				SiteID:           content.SiteID,
				HTMLContent:      content.HtmlContent,
				OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
				LastEditedBy:     content.LastEditedBy,
			}
		}
		return items, nil

	case "postgresql":
		contents, err := c.database.GetPostgreSQLQueries().GetAllContent(context.Background(), siteID)
		if err != nil {
			return nil, err
		}

		items := make(map[string]ContentItem)
		for _, content := range contents {
			items[content.ID] = ContentItem{
				ID:               content.ID,
				SiteID:           content.SiteID,
				HTMLContent:      content.HtmlContent,
				OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
				LastEditedBy:     content.LastEditedBy,
			}
		}
		return items, nil

	default:
		return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
	}
}

// CreateContent creates a new content item
func (c *DatabaseClient) CreateContent(siteID, contentID, htmlContent, originalTemplate, lastEditedBy string) (*ContentItem, error) {
	switch c.database.GetDBType() {
	case "sqlite3":
		content, err := c.database.GetSQLiteQueries().CreateContent(context.Background(), sqlite.CreateContentParams{
			ID:               contentID,
			SiteID:           siteID,
			HtmlContent:      htmlContent,
			OriginalTemplate: toNullString(originalTemplate),
			LastEditedBy:     lastEditedBy,
		})
		if err != nil {
			return nil, err
		}
		return &ContentItem{
			ID:               content.ID,
			SiteID:           content.SiteID,
			HTMLContent:      content.HtmlContent,
			OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
			LastEditedBy:     content.LastEditedBy,
		}, nil

	case "postgresql":
		content, err := c.database.GetPostgreSQLQueries().CreateContent(context.Background(), postgresql.CreateContentParams{
			ID:               contentID,
			SiteID:           siteID,
			HtmlContent:      htmlContent,
			OriginalTemplate: toNullString(originalTemplate),
			LastEditedBy:     lastEditedBy,
		})
		if err != nil {
			return nil, err
		}
		return &ContentItem{
			ID:               content.ID,
			SiteID:           content.SiteID,
			HTMLContent:      content.HtmlContent,
			OriginalTemplate: getStringFromNullString(content.OriginalTemplate),
			LastEditedBy:     content.LastEditedBy,
		}, nil

	default:
		return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
	}
}

// Helper function to convert string to sql.NullString
func toNullString(s string) sql.NullString {
	if s == "" {
		return sql.NullString{Valid: false}
	}
	return sql.NullString{String: s, Valid: true}
}

// GetCollection retrieves a collection container
func (c *DatabaseClient) GetCollection(siteID, collectionID string) (*CollectionItem, error) {
	switch c.database.GetDBType() {
	case "sqlite3":
		collection, err := c.database.GetSQLiteQueries().GetCollection(context.Background(), sqlite.GetCollectionParams{
			ID:     collectionID,
			SiteID: siteID,
		})
		if err != nil {
			return nil, err
		}
		return &CollectionItem{
			ID:            collection.ID,
			SiteID:        collection.SiteID,
			ContainerHTML: collection.ContainerHtml,
			LastEditedBy:  collection.LastEditedBy,
		}, nil

	case "postgresql":
		collection, err := c.database.GetPostgreSQLQueries().GetCollection(context.Background(), postgresql.GetCollectionParams{
			ID:     collectionID,
			SiteID: siteID,
		})
		if err != nil {
			return nil, err
		}
		return &CollectionItem{
			ID:            collection.ID,
			SiteID:        collection.SiteID,
			ContainerHTML: collection.ContainerHtml,
			LastEditedBy:  collection.LastEditedBy,
		}, nil

	default:
		return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
	}
}

// CreateCollection creates a new collection container
func (c *DatabaseClient) CreateCollection(siteID, collectionID, containerHTML, lastEditedBy string) (*CollectionItem, error) {
	switch c.database.GetDBType() {
	case "sqlite3":
		collection, err := c.database.GetSQLiteQueries().CreateCollection(context.Background(), sqlite.CreateCollectionParams{
			ID:            collectionID,
			SiteID:        siteID,
			ContainerHtml: containerHTML,
			LastEditedBy:  lastEditedBy,
		})
		if err != nil {
			return nil, err
		}
		return &CollectionItem{
			ID:            collection.ID,
			SiteID:        collection.SiteID,
			ContainerHTML: collection.ContainerHtml,
			LastEditedBy:  collection.LastEditedBy,
		}, nil

	case "postgresql":
		collection, err := c.database.GetPostgreSQLQueries().CreateCollection(context.Background(), postgresql.CreateCollectionParams{
			ID:            collectionID,
			SiteID:        siteID,
			ContainerHtml: containerHTML,
			LastEditedBy:  lastEditedBy,
		})
		if err != nil {
			return nil, err
		}
		return &CollectionItem{
			ID:            collection.ID,
			SiteID:        collection.SiteID,
			ContainerHTML: collection.ContainerHtml,
			LastEditedBy:  collection.LastEditedBy,
		}, nil

	default:
		return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
	}
}

// GetCollectionItems retrieves all items in a collection with template information
func (c *DatabaseClient) GetCollectionItems(siteID, collectionID string) ([]CollectionItemWithTemplate, error) {
	switch c.database.GetDBType() {
	case "sqlite3":
		items, err := c.database.GetSQLiteQueries().GetCollectionItemsWithTemplate(context.Background(), sqlite.GetCollectionItemsWithTemplateParams{
			CollectionID: collectionID,
			SiteID:       siteID,
		})
		if err != nil {
			return nil, err
		}

		result := make([]CollectionItemWithTemplate, len(items))
		for i, item := range items {
			result[i] = CollectionItemWithTemplate{
				ItemID:       item.ItemID,
				CollectionID: item.CollectionID,
				SiteID:       item.SiteID,
				TemplateID:   int(item.TemplateID),
				HTMLContent:  item.HtmlContent,
				Position:     int(item.Position),
				LastEditedBy: item.LastEditedBy,
				TemplateName: item.TemplateName,
				HTMLTemplate: item.HtmlTemplate,
				IsDefault:    item.IsDefault != 0, // SQLite uses INTEGER for boolean
			}
		}
		return result, nil

	case "postgresql":
		items, err := c.database.GetPostgreSQLQueries().GetCollectionItemsWithTemplate(context.Background(), postgresql.GetCollectionItemsWithTemplateParams{
			CollectionID: collectionID,
			SiteID:       siteID,
		})
		if err != nil {
			return nil, err
		}

		result := make([]CollectionItemWithTemplate, len(items))
		for i, item := range items {
			result[i] = CollectionItemWithTemplate{
				ItemID:       item.ItemID,
				CollectionID: item.CollectionID,
				SiteID:       item.SiteID,
				TemplateID:   int(item.TemplateID),
				HTMLContent:  item.HtmlContent,
				Position:     int(item.Position),
				LastEditedBy: item.LastEditedBy,
				TemplateName: item.TemplateName,
				HTMLTemplate: item.HtmlTemplate,
				IsDefault:    item.IsDefault, // PostgreSQL uses BOOLEAN
			}
		}
		return result, nil

	default:
		return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
	}
}

// CreateCollectionTemplate creates a new template for a collection
func (c *DatabaseClient) CreateCollectionTemplate(siteID, collectionID, name, htmlTemplate string, isDefault bool) (*CollectionTemplateItem, error) {
	switch c.database.GetDBType() {
	case "sqlite3":
		var isDefaultInt int64
		if isDefault {
			isDefaultInt = 1
		}

		template, err := c.database.GetSQLiteQueries().CreateCollectionTemplate(context.Background(), sqlite.CreateCollectionTemplateParams{
			CollectionID: collectionID,
			SiteID:       siteID,
			Name:         name,
			HtmlTemplate: htmlTemplate,
			IsDefault:    isDefaultInt,
		})
		if err != nil {
			return nil, err
		}
		return &CollectionTemplateItem{
			TemplateID:   int(template.TemplateID),
			CollectionID: template.CollectionID,
			SiteID:       template.SiteID,
			Name:         template.Name,
			HTMLTemplate: template.HtmlTemplate,
			IsDefault:    template.IsDefault != 0,
		}, nil

	case "postgresql":
		template, err := c.database.GetPostgreSQLQueries().CreateCollectionTemplate(context.Background(), postgresql.CreateCollectionTemplateParams{
			CollectionID: collectionID,
			SiteID:       siteID,
			Name:         name,
			HtmlTemplate: htmlTemplate,
			IsDefault:    isDefault,
		})
		if err != nil {
			return nil, err
		}
		return &CollectionTemplateItem{
			TemplateID:   int(template.TemplateID),
			CollectionID: template.CollectionID,
			SiteID:       template.SiteID,
			Name:         template.Name,
			HTMLTemplate: template.HtmlTemplate,
			IsDefault:    template.IsDefault,
		}, nil

	default:
		return nil, fmt.Errorf("unsupported database type: %s", c.database.GetDBType())
	}
}
