package content

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

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

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

// DatabaseClient implements ContentClient for direct database access
type DatabaseClient struct {
	db *db.Database
}

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

// GetContent fetches a single content item by ID
func (d *DatabaseClient) GetContent(siteID, contentID string) (*engine.ContentItem, error) {
	ctx := context.Background()
	var content interface{}
	var err error

	switch d.db.GetDBType() {
	case "sqlite3":
		content, err = d.db.GetSQLiteQueries().GetContent(ctx, sqlite.GetContentParams{
			ID:     contentID,
			SiteID: siteID,
		})
	case "postgresql":
		content, err = d.db.GetPostgreSQLQueries().GetContent(ctx, postgresql.GetContentParams{
			ID:     contentID,
			SiteID: siteID,
		})
	default:
		return nil, fmt.Errorf("unsupported database type: %s", d.db.GetDBType())
	}

	if err != nil {
		if err == sql.ErrNoRows {
			return nil, nil // Content not found, return nil without error
		}
		return nil, fmt.Errorf("database error: %w", err)
	}

	item := d.convertToContentItem(content)
	return &item, nil
}

// GetBulkContent fetches multiple content items by IDs
func (d *DatabaseClient) GetBulkContent(siteID string, contentIDs []string) (map[string]engine.ContentItem, error) {
	if len(contentIDs) == 0 {
		return make(map[string]engine.ContentItem), nil
	}

	ctx := context.Background()
	var dbContent interface{}
	var err error

	switch d.db.GetDBType() {
	case "sqlite3":
		dbContent, err = d.db.GetSQLiteQueries().GetBulkContent(ctx, sqlite.GetBulkContentParams{
			SiteID: siteID,
			Ids:    contentIDs,
		})
	case "postgresql":
		dbContent, err = d.db.GetPostgreSQLQueries().GetBulkContent(ctx, postgresql.GetBulkContentParams{
			SiteID: siteID,
			Ids:    contentIDs,
		})
	default:
		return nil, fmt.Errorf("unsupported database type: %s", d.db.GetDBType())
	}

	if err != nil {
		return nil, fmt.Errorf("database error: %w", err)
	}

	items := d.convertToContentItemList(dbContent)

	// Convert slice to map for easy lookup
	result := make(map[string]engine.ContentItem)
	for _, item := range items {
		result[item.ID] = item
	}

	return result, nil
}

// GetAllContent fetches all content for a site
func (d *DatabaseClient) GetAllContent(siteID string) (map[string]engine.ContentItem, error) {
	ctx := context.Background()
	var dbContent interface{}
	var err error

	switch d.db.GetDBType() {
	case "sqlite3":
		dbContent, err = d.db.GetSQLiteQueries().GetAllContent(ctx, siteID)
	case "postgresql":
		dbContent, err = d.db.GetPostgreSQLQueries().GetAllContent(ctx, siteID)
	default:
		return nil, fmt.Errorf("unsupported database type: %s", d.db.GetDBType())
	}

	if err != nil {
		return nil, fmt.Errorf("database error: %w", err)
	}

	items := d.convertToContentItemList(dbContent)

	// Convert slice to map for easy lookup
	result := make(map[string]engine.ContentItem)
	for _, item := range items {
		result[item.ID] = item
	}

	return result, nil
}

// convertToContentItem converts database models to engine.ContentItem
func (d *DatabaseClient) convertToContentItem(content interface{}) engine.ContentItem {
	switch d.db.GetDBType() {
	case "sqlite3":
		c := content.(sqlite.Content)
		return engine.ContentItem{
			ID:               c.ID,
			SiteID:           c.SiteID,
			HTMLContent:      c.HtmlContent,
			OriginalTemplate: getStringFromNullString(c.OriginalTemplate),
			UpdatedAt:        time.Unix(c.UpdatedAt, 0).Format(time.RFC3339),
		}
	case "postgresql":
		c := content.(postgresql.Content)
		return engine.ContentItem{
			ID:               c.ID,
			SiteID:           c.SiteID,
			HTMLContent:      c.HtmlContent,
			OriginalTemplate: getStringFromNullString(c.OriginalTemplate),
			UpdatedAt:        time.Unix(c.UpdatedAt, 0).Format(time.RFC3339),
		}
	}
	return engine.ContentItem{} // Should never happen
}

// convertToContentItemList converts database model lists to engine.ContentItem slice
func (d *DatabaseClient) convertToContentItemList(contentList interface{}) []engine.ContentItem {
	switch d.db.GetDBType() {
	case "sqlite3":
		list := contentList.([]sqlite.Content)
		items := make([]engine.ContentItem, len(list))
		for i, content := range list {
			items[i] = d.convertToContentItem(content)
		}
		return items
	case "postgresql":
		list := contentList.([]postgresql.Content)
		items := make([]engine.ContentItem, len(list))
		for i, content := range list {
			items[i] = d.convertToContentItem(content)
		}
		return items
	}
	return []engine.ContentItem{} // Should never happen
}

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

	case "postgresql":
		content, err := c.db.GetPostgreSQLQueries().CreateContent(context.Background(), postgresql.CreateContentParams{
			ID:               contentID,
			SiteID:           siteID,
			HtmlContent:      htmlContent,
			OriginalTemplate: toNullString(originalTemplate),
			LastEditedBy:     lastEditedBy,
		})
		if err != nil {
			return nil, err
		}
		return &engine.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.db.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}
}

// Collection method stubs - TODO: Implement these
func (d *DatabaseClient) GetCollection(siteID, collectionID string) (*engine.CollectionItem, error) {
	return nil, fmt.Errorf("collection operations not implemented in content.DatabaseClient")
}

func (d *DatabaseClient) CreateCollection(siteID, collectionID, containerHTML, lastEditedBy string) (*engine.CollectionItem, error) {
	return nil, fmt.Errorf("collection operations not implemented in content.DatabaseClient")
}

func (d *DatabaseClient) GetCollectionItems(siteID, collectionID string) ([]engine.CollectionItemWithTemplate, error) {
	return nil, fmt.Errorf("collection operations not implemented in content.DatabaseClient")
}

func (d *DatabaseClient) CreateCollectionTemplate(siteID, collectionID, name, htmlTemplate string, isDefault bool) (*engine.CollectionTemplateItem, error) {
	return nil, fmt.Errorf("collection operations not implemented in content.DatabaseClient")
}
