package domain

import (
	"database/sql/driver"
	"encoding/json"
	"errors"
	"fmt"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
	"time"
)

// JSONB is a custom type for JSONB columns.
type JSONB map[string]interface{}

// Value marshals JSONB for storing in the DB.
func (j JSONB) Value() (driver.Value, error) {
	if j == nil {
		return "{}", nil
	}
	return json.Marshal(j)
}

// Scan unmarshals a JSONB value.
func (j *JSONB) Scan(value interface{}) error {
	if value == nil {
		*j = JSONB{}
		return nil
	}
	switch v := value.(type) {
	case []byte:
		if len(v) == 0 {
			*j = JSONB{}
			return nil
		}
		return json.Unmarshal(v, j)
	case string:
		if v == "" {
			*j = JSONB{}
			return nil
		}
		return json.Unmarshal([]byte(v), j)
	default:
		return fmt.Errorf("failed to unmarshal JSONB value of type %T: %v", value, value)
	}
}

// BaseModel contains common fields for all models
type BaseModel struct {
	ID        uint `gorm:"primaryKey"`
	CreatedAt time.Time
	UpdatedAt time.Time
}

// TranslatableModel extends BaseModel with language support
type TranslatableModel struct {
	BaseModel
	Language string `gorm:"size:50;default:'multi'"`
	Slug     string `gorm:"size:255;index"`
}

// Translation status enum
type TranslationStatus string

const (
	TranslationStatusDraft     TranslationStatus = "draft"
	TranslationStatusPublished TranslationStatus = "published"
	TranslationStatusReviewing TranslationStatus = "reviewing"
	TranslationStatusRejected  TranslationStatus = "rejected"
)

// UserRole enum
type UserRole string

const (
	UserRoleReader      UserRole = "reader"
	UserRoleContributor UserRole = "contributor"
	UserRoleReviewer    UserRole = "reviewer"
	UserRoleEditor      UserRole = "editor"
	UserRoleAdmin       UserRole = "admin"
)

// User represents a user of the platform
type User struct {
	BaseModel
	Username    string   `gorm:"size:50;not null;unique"`
	Email       string   `gorm:"size:100;not null;unique"`
	Password    string   `gorm:"size:255;not null"`
	FirstName   string   `gorm:"size:50"`
	LastName    string   `gorm:"size:50"`
	DisplayName string   `gorm:"size:100"`
	Bio         string   `gorm:"type:text"`
	AvatarURL   string   `gorm:"size:255"`
	Role        UserRole `gorm:"size:20;default:'reader'"`
	LastLoginAt *time.Time
	Verified    bool `gorm:"default:false"`
	Active      bool `gorm:"default:true"`
	Translations  []*Translation  `gorm:"foreignKey:TranslatorID"`
	Comments      []*Comment      `gorm:"foreignKey:UserID"`
	Likes         []*Like         `gorm:"foreignKey:UserID"`
	Bookmarks     []*Bookmark     `gorm:"foreignKey:UserID"`
	Collections   []*Collection   `gorm:"foreignKey:UserID"`
	Contributions []*Contribution `gorm:"foreignKey:UserID"`
	CountryID *uint
	Country   *Country `gorm:"foreignKey:CountryID"`
	CityID    *uint
	City      *City `gorm:"foreignKey:CityID"`
	AddressID *uint
	Address   *Address `gorm:"foreignKey:AddressID"`
}

// UserProfile represents additional profile information for a user
type UserProfile struct {
	BaseModel
	UserID      uint   `gorm:"uniqueIndex"`
	User        *User  `gorm:"foreignKey:UserID"`
	PhoneNumber string `gorm:"size:20"`
	Website     string `gorm:"size:255"`
	Twitter     string `gorm:"size:50"`
	Facebook    string `gorm:"size:50"`
	LinkedIn    string `gorm:"size:50"`
	Github      string `gorm:"size:50"`
	Preferences JSONB  `gorm:"type:jsonb;default:'{}'"`
	Settings    JSONB  `gorm:"type:jsonb;default:'{}'"`
}

// UserSession represents a user session
type UserSession struct {
	BaseModel
	UserID    uint   `gorm:"index"`
	User      *User  `gorm:"foreignKey:UserID"`
	Token     string `gorm:"size:255;not null;uniqueIndex"`
	IP        string    `gorm:"size:50"`
	UserAgent string    `gorm:"size:255"`
	ExpiresAt time.Time `gorm:"not null"`
}

// PasswordReset represents a password reset request
type PasswordReset struct {
	BaseModel
	UserID    uint   `gorm:"index"`
	User      *User  `gorm:"foreignKey:UserID"`
	Token     string `gorm:"size:255;not null;uniqueIndex"`
	ExpiresAt time.Time `gorm:"not null"`
	Used      bool      `gorm:"default:false"`
}

// EmailVerification represents an email verification request
type EmailVerification struct {
	BaseModel
	UserID    uint   `gorm:"index"`
	User      *User  `gorm:"foreignKey:UserID"`
	Token     string `gorm:"size:255;not null;uniqueIndex"`
	ExpiresAt time.Time `gorm:"not null"`
	Used      bool      `gorm:"default:false"`
}

func (u *User) SetPassword(password string) error {
	if password == "" {
		return errors.New("password cannot be empty")
	}
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return errors.New("failed to hash password: " + err.Error())
	}
	u.Password = string(hashedPassword)
	return nil
}

func (u *User) BeforeSave(tx *gorm.DB) error {
	if u.Password == "" {
		return nil
	}
	if len(u.Password) >= 60 && u.Password[:4] == "$2a$" {
		return nil
	}
	return u.SetPassword(u.Password)
}

func (u *User) CheckPassword(password string) bool {
	err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password))
	return err == nil
}


type AuthorStatus string
const (
	AuthorStatusActive   AuthorStatus = "active"
	AuthorStatusInactive AuthorStatus = "inactive"
	AuthorStatusDeceased AuthorStatus = "deceased"
)
type Author struct {
	TranslatableModel
	Name          string       `gorm:"size:255;not null"`
	Status        AuthorStatus `gorm:"size:50;default:'active'"`
	BirthDate     *time.Time
	DeathDate     *time.Time
	OpenLibraryID string       `gorm:"size:50;index"`
	Books         []*Book `gorm:"many2many:book_authors"`
	CountryID     *uint
	Country       *Country `gorm:"foreignKey:CountryID"`
	CityID        *uint
	City          *City `gorm:"foreignKey:CityID"`
	PlaceID       *uint
	Place         *Place `gorm:"foreignKey:PlaceID"`
	AddressID     *uint
	Address       *Address       `gorm:"foreignKey:AddressID"`
	Translations  []*Translation `gorm:"polymorphic:Translatable"`
	Copyrights    []*Copyright `gorm:"many2many:author_copyrights;constraint:OnDelete:CASCADE"`
	Monetizations []*Monetization `gorm:"many2many:author_monetizations;constraint:OnDelete:CASCADE"`
}

type BookStatus string
const (
	BookStatusDraft      BookStatus = "draft"
	BookStatusPublished  BookStatus = "published"
	BookStatusOutOfPrint BookStatus = "out_of_print"
	BookStatusArchived   BookStatus = "archived"
)
type BookFormat string
const (
	BookFormatHardcover BookFormat = "hardcover"
	BookFormatPaperback BookFormat = "paperback"
	BookFormatEbook     BookFormat = "ebook"
	BookFormatAudiobook BookFormat = "audiobook"
	BookFormatDigital   BookFormat = "digital"
)
type Book struct {
	TranslatableModel
	Title         string     `gorm:"size:255;not null"`
	Description   string     `gorm:"type:text"`
	ISBN          string     `gorm:"size:20;index"`
	Format        BookFormat `gorm:"size:50;default:'paperback'"`
	Status        BookStatus `gorm:"size:50;default:'draft'"`
	PublishedAt   *time.Time
	Authors       []*Author `gorm:"many2many:book_authors"`
	PublisherID   *uint
	Publisher     *Publisher     `gorm:"foreignKey:PublisherID"`
	Translations  []*Translation `gorm:"polymorphic:Translatable"`
	Copyrights    []*Copyright `gorm:"many2many:book_copyrights;constraint:OnDelete:CASCADE"`
	Monetizations []*Monetization `gorm:"many2many:book_monetizations;constraint:OnDelete:CASCADE"`
}

type PublisherStatus string
const (
	PublisherStatusActive   PublisherStatus = "active"
	PublisherStatusInactive PublisherStatus = "inactive"
	PublisherStatusDefunct  PublisherStatus = "defunct"
)
type Publisher struct {
	TranslatableModel
	Name          string          `gorm:"size:255;not null"`
	Description   string          `gorm:"type:text"`
	Status        PublisherStatus `gorm:"size:50;default:'active'"`
	Books         []*Book         `gorm:"foreignKey:PublisherID"`
	CountryID     *uint
	Country       *Country       `gorm:"foreignKey:CountryID"`
	Translations  []*Translation `gorm:"polymorphic:Translatable"`
	Copyrights    []*Copyright `gorm:"many2many:publisher_copyrights;constraint:OnDelete:CASCADE"`
	Monetizations []*Monetization `gorm:"many2many:publisher_monetizations;constraint:OnDelete:CASCADE"`
}

type SourceStatus string
const (
	SourceStatusActive   SourceStatus = "active"
	SourceStatusInactive SourceStatus = "inactive"
	SourceStatusArchived SourceStatus = "archived"
)
type Source struct {
	TranslatableModel
	Name          string         `gorm:"size:255;not null"`
	Description   string         `gorm:"type:text"`
	URL           string         `gorm:"size:512"`
	Status        SourceStatus   `gorm:"size:50;default:'active'"`
	Translations  []*Translation `gorm:"polymorphic:Translatable"`
	Copyrights    []*Copyright `gorm:"many2many:source_copyrights;constraint:OnDelete:CASCADE"`
	Monetizations []*Monetization `gorm:"many2many:source_monetizations;constraint:OnDelete:CASCADE"`
}

type EditionStatus string
const (
	EditionStatusDraft      EditionStatus = "draft"
	EditionStatusPublished  EditionStatus = "published"
	EditionStatusOutOfPrint EditionStatus = "out_of_print"
	EditionStatusArchived   EditionStatus = "archived"
)
type Edition struct {
	BaseModel
	Title       string        `gorm:"size:255;not null"`
	Description string        `gorm:"type:text"`
	ISBN        string        `gorm:"size:20;index"`
	Version     string        `gorm:"size:50"`
	Format      BookFormat    `gorm:"size:50;default:'paperback'"`
	Status      EditionStatus `gorm:"size:50;default:'draft'"`
	PublishedAt *time.Time
	BookID      uint
	Book        *Book `gorm:"foreignKey:BookID"`
}

func (a *Author) BeforeSave(tx *gorm.DB) error {
	if a.Name == "" {
		a.Name = "Unknown Author"
	}
	return nil
}
func (b *Book) BeforeSave(tx *gorm.DB) error {
	if b.Title == "" {
		b.Title = "Untitled Book"
	}
	return nil
}
func (p *Publisher) BeforeSave(tx *gorm.DB) error {
	if p.Name == "" {
		p.Name = "Unknown Publisher"
	}
	return nil
}

type Comment struct {
	BaseModel
	Text          string `gorm:"type:text;not null"`
	UserID        uint
	User          *User `gorm:"foreignKey:UserID"`
	WorkID        *uint
	TranslationID *uint
	Translation   *Translation `gorm:"foreignKey:TranslationID"`
	LineNumber    *int         `gorm:"index"`
	TextBlockID   *uint
	TextBlock     *TextBlock `gorm:"foreignKey:TextBlockID"`
	ParentID      *uint
	Parent        *Comment   `gorm:"foreignKey:ParentID"`
	Children      []*Comment `gorm:"foreignKey:ParentID"`
	Likes         []*Like    `gorm:"foreignKey:CommentID"`
}
type Like struct {
	BaseModel
	UserID        uint `gorm:"index;uniqueIndex:uniq_like_user_target"`
	User          *User `gorm:"foreignKey:UserID"`
	WorkID        *uint `gorm:"index;uniqueIndex:uniq_like_user_target"`
	TranslationID *uint `gorm:"index;uniqueIndex:uniq_like_user_target"`
	Translation   *Translation `gorm:"foreignKey:TranslationID"`
	CommentID     *uint `gorm:"index;uniqueIndex:uniq_like_user_target"`
	Comment       *Comment `gorm:"foreignKey:CommentID"`
}
type Bookmark struct {
	BaseModel
	Name       string `gorm:"size:100"`
	UserID     uint   `gorm:"index;uniqueIndex:uniq_bookmark_user_work"`
	User       *User  `gorm:"foreignKey:UserID"`
	WorkID     uint   `gorm:"index;uniqueIndex:uniq_bookmark_user_work"`
	Notes      string `gorm:"type:text"`
	LastReadAt *time.Time
	Progress   int `gorm:"default:0"`
}
type Collection struct {
	TranslatableModel
	Name          string `gorm:"size:100;not null"`
	Description   string `gorm:"type:text"`
	UserID        uint
	User          *User   `gorm:"foreignKey:UserID"`
	IsPublic      bool    `gorm:"default:true"`
	CoverImageURL string  `gorm:"size:255"`
}

type CollectionWork struct {
	CollectionID uint `gorm:"primaryKey"`
	WorkID       uint `gorm:"primaryKey"`
}
type Contribution struct {
	BaseModel
	Name          string `gorm:"size:100;not null"`
	Status        string `gorm:"size:20;default:'draft'"`
	UserID        uint
	User          *User `gorm:"foreignKey:UserID"`
	WorkID        *uint
	TranslationID *uint
	Translation   *Translation `gorm:"foreignKey:TranslationID"`
	ReviewerID    *uint
	Reviewer      *User `gorm:"foreignKey:ReviewerID"`
	ReviewedAt    *time.Time
	Feedback      string `gorm:"type:text"`
}

type Country struct {
	TranslatableModel
	Name      string `gorm:"size:100;not null"`
	Code      string `gorm:"size:2;not null;uniqueIndex"`
	PhoneCode string `gorm:"size:10"`
	Currency  string `gorm:"size:3"`
	Continent string `gorm:"size:20"`
	Cities    []*City    `gorm:"foreignKey:CountryID"`
	Places    []*Place   `gorm:"foreignKey:CountryID"`
	Addresses []*Address `gorm:"foreignKey:CountryID"`
}
type Language struct {
	BaseModel
	Code      string `gorm:"size:16;not null;uniqueIndex"`
	Name      string `gorm:"size:100;not null"`
	Script    string `gorm:"size:20"`
	Direction string `gorm:"size:5"`
}
type City struct {
	TranslatableModel
	Name      string `gorm:"size:100;not null"`
	CountryID uint
	Country   *Country `gorm:"foreignKey:CountryID"`
	Places    []*Place   `gorm:"foreignKey:CityID"`
	Addresses []*Address `gorm:"foreignKey:CityID"`
}
type Place struct {
	TranslatableModel
	Name        string `gorm:"size:100;not null"`
	Description string `gorm:"type:text"`
	Latitude    float64
	Longitude   float64
	CountryID   *uint
	Country     *Country `gorm:"foreignKey:CountryID"`
	CityID      *uint
	City        *City `gorm:"foreignKey:CityID"`
}
type Address struct {
	BaseModel
	Street       string `gorm:"size:255"`
	StreetNumber string `gorm:"size:20"`
	PostalCode   string `gorm:"size:20"`
	CountryID    *uint
	Country      *Country `gorm:"foreignKey:CountryID"`
	CityID       *uint
	City         *City `gorm:"foreignKey:CityID"`
	Latitude     *float64
	Longitude    *float64
}

type Tag struct {
	BaseModel
	Name        string  `gorm:"size:100;not null;uniqueIndex"`
	Description string  `gorm:"type:text"`
	Slug        string  `gorm:"size:255;index"`
}
type Category struct {
	BaseModel
	Name        string `gorm:"size:100;not null;uniqueIndex"`
	Description string `gorm:"type:text"`
	ParentID    *uint
	Parent      *Category   `gorm:"foreignKey:ParentID"`
	Children    []*Category `gorm:"foreignKey:ParentID"`
	Path        string      `gorm:"size:1024;index"`
	Slug        string      `gorm:"size:255;index"`
}
type Series struct {
	BaseModel
	Name        string `gorm:"size:255;not null;uniqueIndex"`
	Description string `gorm:"type:text"`
}

type Translation struct {
	BaseModel
	Title            string            `gorm:"size:255;not null"`
	Content          string            `gorm:"type:text"`
	Description      string            `gorm:"type:text"`
	Language         string            `gorm:"size:50;not null;uniqueIndex:idx_translation_target_language"`
	Status           TranslationStatus `gorm:"size:50;default:'draft'"`
	PublishedAt      *time.Time
	TranslatableID   uint   `gorm:"not null;uniqueIndex:idx_translation_target_language"`
	TranslatableType string `gorm:"size:50;not null;uniqueIndex:idx_translation_target_language"`
	TranslatorID     *uint
	Translator       *User `gorm:"foreignKey:TranslatorID"`
	IsOriginalLanguage bool `gorm:"default:false"`
	AudioURL           string `gorm:"size:512"`
	DateTranslated     *time.Time
}
type TranslationField struct {
	BaseModel
	TranslationID uint
	Translation   *Translation `gorm:"foreignKey:TranslationID"`
	FieldName     string       `gorm:"size:100;not null"`
	FieldValue    string       `gorm:"type:text;not null"`
	Language      string       `gorm:"size:50;not null"`
}
type TranslatableEntity interface {
	GetID() uint
	GetType() string
	GetDefaultLanguage() string
}
func GetTranslatableFields(entityType string) []string {
	fieldMappings := map[string][]string{
		"Work":      {"title", "content", "description"},
		"Author":    {"name", "biography"},
		"Book":      {"title", "description"},
		"Country":   {"name"},
		"Publisher": {"name", "description"},
		"Source":    {"name", "description"},
	}
	if fields, exists := fieldMappings[entityType]; exists {
		return fields
	}
	return []string{}
}
func (t *Translation) BeforeSave(tx *gorm.DB) error {
	if t.Title == "" {
		t.Title = "Untitled Translation"
	}
	return nil
}
func (a *Author) GetID() uint                { return a.ID }
func (a *Author) GetType() string            { return "Author" }
func (a *Author) GetDefaultLanguage() string { return a.Language }
func (b *Book) GetID() uint                { return b.ID }
func (b *Book) GetType() string            { return "Book" }
func (b *Book) GetDefaultLanguage() string { return b.Language }
func (c *Country) GetID() uint                { return c.ID }
func (c *Country) GetType() string            { return "Country" }
func (c *Country) GetDefaultLanguage() string { return c.Language }
func (p *Publisher) GetID() uint                { return p.ID }
func (p *Publisher) GetType() string            { return "Publisher" }
func (p *Publisher) GetDefaultLanguage() string { return p.Language }
func (s *Source) GetID() uint                { return s.ID }
func (s *Source) GetType() string            { return "Source" }
func (s *Source) GetDefaultLanguage() string { return s.Language }

type Copyright struct {
	BaseModel
	Identificator string `gorm:"size:100;not null"`
	Name          string `gorm:"size:255;not null"`
	Description   string `gorm:"type:text"`
	License       string `gorm:"size:100"`
	StartDate     *time.Time
	EndDate       *time.Time
	Translations []CopyrightTranslation `gorm:"foreignKey:CopyrightID"`
}

type AuthorCopyright struct {
    AuthorID    uint `gorm:"primaryKey;index"`
    CopyrightID uint `gorm:"primaryKey;index"`
    CreatedAt   time.Time
}

func (AuthorCopyright) TableName() string { return "author_copyrights" }

type BookCopyright struct {
    BookID      uint `gorm:"primaryKey;index"`
    CopyrightID uint `gorm:"primaryKey;index"`
    CreatedAt   time.Time
}

func (BookCopyright) TableName() string { return "book_copyrights" }

type PublisherCopyright struct {
    PublisherID uint `gorm:"primaryKey;index"`
    CopyrightID uint `gorm:"primaryKey;index"`
    CreatedAt   time.Time
}

func (PublisherCopyright) TableName() string { return "publisher_copyrights" }

type SourceCopyright struct {
    SourceID    uint `gorm:"primaryKey;index"`
    CopyrightID uint `gorm:"primaryKey;index"`
    CreatedAt   time.Time
}

func (SourceCopyright) TableName() string { return "source_copyrights" }
type CopyrightTranslation struct {
	BaseModel
	CopyrightID  uint
	Copyright    *Copyright `gorm:"foreignKey:CopyrightID"`
	LanguageCode string     `gorm:"size:10;not null"`
	Message      string     `gorm:"type:text;not null"`
	Description  string     `gorm:"type:text"`
}
type CopyrightClaimStatus string
const (
	CopyrightClaimStatusPending  CopyrightClaimStatus = "pending"
	CopyrightClaimStatusApproved CopyrightClaimStatus = "approved"
	CopyrightClaimStatusRejected CopyrightClaimStatus = "rejected"
)
type CopyrightClaim struct {
	BaseModel
	Details   string               `gorm:"type:text;not null"`
	Status    CopyrightClaimStatus `gorm:"size:50;default:'pending'"`
	ClaimDate time.Time            `gorm:"not null"`
	Resolution string               `gorm:"type:text"`
	ResolvedAt *time.Time
	UserID     *uint
	User       *User `gorm:"foreignKey:UserID"`
	WorkID     *uint
	Work       *Work `gorm:"foreignKey:WorkID"`
}
type MonetizationType string
const (
	MonetizationTypeSubscription  MonetizationType = "subscription"
	MonetizationTypeOneTime       MonetizationType = "one_time"
	MonetizationTypeDonation      MonetizationType = "donation"
	MonetizationTypeAdvertisement MonetizationType = "advertisement"
	MonetizationTypeLicensing     MonetizationType = "licensing"
)
type MonetizationStatus string
const (
	MonetizationStatusActive   MonetizationStatus = "active"
	MonetizationStatusInactive MonetizationStatus = "inactive"
	MonetizationStatusPending  MonetizationStatus = "pending"
)

type AuthorMonetization struct {
    AuthorID       uint `gorm:"primaryKey;index"`
    MonetizationID uint `gorm:"primaryKey;index"`
    CreatedAt      time.Time
}

func (AuthorMonetization) TableName() string { return "author_monetizations" }

type BookMonetization struct {
    BookID         uint `gorm:"primaryKey;index"`
    MonetizationID uint `gorm:"primaryKey;index"`
    CreatedAt      time.Time
}

func (BookMonetization) TableName() string { return "book_monetizations" }

type PublisherMonetization struct {
    PublisherID    uint `gorm:"primaryKey;index"`
    MonetizationID uint `gorm:"primaryKey;index"`
    CreatedAt      time.Time
}

func (PublisherMonetization) TableName() string { return "publisher_monetizations" }

type SourceMonetization struct {
    SourceID       uint `gorm:"primaryKey;index"`
    MonetizationID uint `gorm:"primaryKey;index"`
    CreatedAt      time.Time
}

func (SourceMonetization) TableName() string { return "source_monetizations" }
type Monetization struct {
	BaseModel
	Amount    float64            `gorm:"type:decimal(10,2);default:0.0"`
	Currency  string             `gorm:"size:3;default:'USD'"`
	Type      MonetizationType   `gorm:"size:50"`
	Status    MonetizationStatus `gorm:"size:50;default:'active'"`
	StartDate *time.Time
	EndDate   *time.Time
	Language  string `gorm:"size:50;not null"`
}
type License struct {
	BaseModel
	SPDXIdentifier string `gorm:"size:64;uniqueIndex"`
	Name           string `gorm:"size:255;not null"`
	URL            string `gorm:"size:512"`
	Description    string `gorm:"type:text"`
}
type ModerationFlag struct {
	BaseModel
	TargetType string `gorm:"size:50;not null"`
	TargetID   uint   `gorm:"not null"`
	Reason     string `gorm:"size:255"`
	Status     string `gorm:"size:50;default:'open'"`
	ReviewerID *uint
	Reviewer   *User  `gorm:"foreignKey:ReviewerID"`
	Notes      string `gorm:"type:text"`
}
type AuditLog struct {
	BaseModel
	ActorID  *uint
	Actor    *User     `gorm:"foreignKey:ActorID"`
	Action   string    `gorm:"size:50;not null"`
	EntityType string    `gorm:"size:50;not null"`
	EntityID uint      `gorm:"not null"`
	Before   JSONB     `gorm:"type:jsonb;default:'{}'"`
	After    JSONB     `gorm:"type:jsonb;default:'{}'"`
	At       time.Time `gorm:"autoCreateTime"`
}

// And all other models from the files I read...
// This is getting very long, but it's the correct approach.
// I will just paste the rest of the structs here.

type TranslationStats struct {
	BaseModel
	Views         int64   `gorm:"default:0"`
	Likes         int64   `gorm:"default:0"`
	Comments      int64   `gorm:"default:0"`
	Shares        int64   `gorm:"default:0"`
	ReadingTime   int     `gorm:"default:0"`
	Sentiment     float64 `gorm:"type:decimal(5,2);default:0.0"`
	TranslationID uint    `gorm:"uniqueIndex;index"`
	Translation   *Translation `gorm:"foreignKey:TranslationID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
}

type UserEngagement struct {
	BaseModel
	UserID         uint      `gorm:"index;uniqueIndex:uniq_user_engagement_date"`
	User           *User     `gorm:"foreignKey:UserID"`
	Date           time.Time `gorm:"type:date;uniqueIndex:uniq_user_engagement_date"`
	WorksRead      int       `gorm:"default:0"`
	CommentsMade   int       `gorm:"default:0"`
	LikesGiven     int       `gorm:"default:0"`
	BookmarksMade  int       `gorm:"default:0"`
	TranslationsMade int     `gorm:"default:0"`
}

type Trending struct {
	BaseModel
	EntityType string    `gorm:"size:50;not null;index:idx_trending_entity_period_date,uniqueIndex:uniq_trending_rank"`
	EntityID   uint      `gorm:"not null;index:idx_trending_entity_period_date,uniqueIndex:uniq_trending_rank"`
	Rank       int       `gorm:"not null;uniqueIndex:uniq_trending_rank"`
	Score      float64   `gorm:"type:decimal(10,2);default:0.0"`
	TimePeriod string    `gorm:"size:50;not null;index:idx_trending_entity_period_date,uniqueIndex:uniq_trending_rank"`
	Date       time.Time `gorm:"type:date;index:idx_trending_entity_period_date,uniqueIndex:uniq_trending_rank"`
}

type BookStats struct {
	BaseModel
	Sales  int64 `gorm:"default:0"`
	Views  int64 `gorm:"default:0"`
	Likes  int64 `gorm:"default:0"`
	BookID uint  `gorm:"uniqueIndex;index"`
	Book   *Book `gorm:"foreignKey:BookID"`
}
type CollectionStats struct {
	BaseModel
	Items        int64 `gorm:"default:0"`
	Views        int64 `gorm:"default:0"`
	Likes        int64 `gorm:"default:0"`
	CollectionID uint `gorm:"uniqueIndex;index"`
	Collection   *Collection `gorm:"foreignKey:CollectionID"`
}
type MediaStats struct {
	BaseModel
	Views     int64 `gorm:"default:0"`
	Downloads int64 `gorm:"default:0"`
	Shares    int64 `gorm:"default:0"`
	MediaID   uint `gorm:"uniqueIndex;index"`
	Media     interface{} `gorm:"-"`
}

type AuthorCountry struct {
	BaseModel
	AuthorID  uint `gorm:"index;uniqueIndex:uniq_author_country"`
	Author    *Author `gorm:"foreignKey:AuthorID"`
	CountryID uint `gorm:"index;uniqueIndex:uniq_author_country"`
	Country   *Country `gorm:"foreignKey:CountryID"`
}
type BookAuthor struct {
	BaseModel
	BookID   uint `gorm:"index;uniqueIndex:uniq_book_author_role"`
	Book     *Book `gorm:"foreignKey:BookID"`
	AuthorID uint `gorm:"index;uniqueIndex:uniq_book_author_role"`
	Author   *Author `gorm:"foreignKey:AuthorID"`
	Role     string  `gorm:"size:50;default:'author';uniqueIndex:uniq_book_author_role"`
	Ordinal  int     `gorm:"default:0"`
}

type ReadabilityScore struct {
	BaseModel
	Score    float64 `gorm:"type:decimal(5,2)"`
	Language string  `gorm:"size:50;not null"`
	Method   string  `gorm:"size:50"`
	WorkID   uint
}
type WritingStyle struct {
	BaseModel
	Name        string `gorm:"size:100;not null"`
	Description string `gorm:"type:text"`
	Language    string `gorm:"size:50;not null"`
	WorkID      uint
}
type LinguisticLayer struct {
	BaseModel
	Name   string `gorm:"size:100;not null"`
	Description string `gorm:"type:text"`
	Language    string `gorm:"size:50;not null"`
	Type        string `gorm:"size:50"`
	WorkID uint
	Data   JSONB `gorm:"type:jsonb;default:'{}'"`
}
type TextBlock struct {
	BaseModel
	WorkID        *uint
	TranslationID *uint
	Translation   *Translation `gorm:"foreignKey:TranslationID"`
	Index         int          `gorm:"index"`
	Type          string       `gorm:"size:30"`
	StartOffset   int          `gorm:"default:0"`
	EndOffset     int          `gorm:"default:0"`
	Text          string       `gorm:"type:text"`
}
type TextMetadata struct {
	BaseModel
	Analysis              string  `gorm:"type:text"`
	Language              string  `gorm:"size:50;not null"`
	WordCount             int     `gorm:"default:0"`
	SentenceCount         int     `gorm:"default:0"`
	ParagraphCount        int     `gorm:"default:0"`
	AverageWordLength     float64 `gorm:"type:decimal(5,2)"`
	AverageSentenceLength float64 `gorm:"type:decimal(5,2)"`
	WorkID                uint
}
type PoeticAnalysis struct {
	BaseModel
	Structure   string `gorm:"type:text"`
	Language    string `gorm:"size:50;not null"`
	RhymeScheme string `gorm:"size:100"`
	MeterType   string `gorm:"size:50"`
	StanzaCount int    `gorm:"default:0"`
	LineCount   int    `gorm:"default:0"`
	WorkID      uint
}
type Word struct {
	BaseModel
	Text         string `gorm:"size:100;not null"`
	Language     string `gorm:"size:50;not null"`
	PartOfSpeech string `gorm:"size:20"`
	Lemma        string `gorm:"size:100"`
	ConceptID    *uint
	Concept      *Concept `gorm:"foreignKey:ConceptID"`
}
type WordOccurrence struct {
	BaseModel
	TextBlockID  uint
	TextBlock    *TextBlock `gorm:"foreignKey:TextBlockID"`
	WordID       *uint
	Word         *Word `gorm:"foreignKey:WordID"`
	StartOffset  int   `gorm:"default:0"`
	EndOffset    int    `gorm:"default:0"`
	Lemma        string `gorm:"size:100"`
	PartOfSpeech string `gorm:"size:20"`
}
type Concept struct {
	BaseModel
	Name        string  `gorm:"size:100;not null"`
	Description string  `gorm:"type:text"`
	Words       []*Word `gorm:"foreignKey:ConceptID"`
}
type LanguageEntity struct {
	BaseModel
	Name     string  `gorm:"size:100;not null"`
	Type     string  `gorm:"size:50"`
	Language string  `gorm:"size:50;not null"`
}
type EntityOccurrence struct {
	BaseModel
	TextBlockID      uint
	TextBlock        *TextBlock `gorm:"foreignKey:TextBlockID"`
	LanguageEntityID uint
	LanguageEntity   *LanguageEntity `gorm:"foreignKey:LanguageEntityID"`
	StartOffset      int             `gorm:"default:0"`
	EndOffset        int             `gorm:"default:0"`
}

type LanguageAnalysis struct {
	BaseModel
	Language string `gorm:"size:50;not null;uniqueIndex:uniq_work_language_analysis"`
	Analysis JSONB  `gorm:"type:jsonb;default:'{}'"`
	WorkID   uint   `gorm:"index;uniqueIndex:uniq_work_language_analysis"`
}
type Gamification struct {
	BaseModel
	Points  int   `gorm:"default:0"`
	Level   int   `gorm:"default:1"`
	Badges  JSONB `gorm:"type:jsonb;default:'{}'"`
	Streaks int   `gorm:"default:0"`
	LastActive *time.Time
	UserID  uint `gorm:"uniqueIndex;index"`
	User    *User `gorm:"foreignKey:UserID"`
}
type Stats struct {
	BaseModel
	Data   JSONB  `gorm:"type:jsonb;default:'{}'"`
	Period string `gorm:"size:50"`
	StartDate time.Time
	EndDate   time.Time
	UserID *uint
	User   *User `gorm:"foreignKey:UserID"`
	WorkID *uint
}
type SearchDocument struct {
	BaseModel
	EntityType   string `gorm:"size:50;index"`
	EntityID     uint   `gorm:"index"`
	LanguageCode string `gorm:"size:16;index"`
	Title        string `gorm:"size:512"`
	Body         string `gorm:"type:text"`
	Keywords     string `gorm:"type:text"`
}

type Emotion struct {
	BaseModel
	Name         string  `gorm:"size:100;not null"`
	Description  string  `gorm:"type:text"`
	Language     string  `gorm:"size:50;not null"`
	Intensity    float64 `gorm:"type:decimal(5,2);default:0.0"`
	UserID       *uint
	User         *User `gorm:"foreignKey:UserID"`
	WorkID       *uint
	CollectionID *uint
	Collection   *Collection `gorm:"foreignKey:CollectionID"`
}
type Mood struct {
	BaseModel
	Name        string  `gorm:"size:100;not null"`
	Description string  `gorm:"type:text"`
	Language    string  `gorm:"size:50;not null"`
}
type TopicCluster struct {
	BaseModel
	Name        string  `gorm:"size:100;not null"`
	Description string  `gorm:"type:text"`
	Keywords    string  `gorm:"type:text"`
}

type Edge struct {
	BaseModel
	SourceTable string `gorm:"size:50;not null;index:idx_edge_source;uniqueIndex:uniq_edge"`
	SourceID    uint   `gorm:"not null;index:idx_edge_source;uniqueIndex:uniq_edge"`
	TargetTable string `gorm:"size:50;not null;index:idx_edge_target;uniqueIndex:uniq_edge"`
	TargetID    uint   `gorm:"not null;index:idx_edge_target;uniqueIndex:uniq_edge"`
	Relation    string `gorm:"size:50;default:'ASSOCIATED_WITH';not null;index;uniqueIndex:uniq_edge"`
	Language    string `gorm:"size:10;default:'en';index;uniqueIndex:uniq_edge"`
	Extra       JSONB  `gorm:"type:jsonb;default:'{}'"`
}
type Embedding struct {
	BaseModel
	ExternalID    string `gorm:"size:64;index"`
	EntityType    string `gorm:"size:50;not null;index:idx_embedding_entity;uniqueIndex:uniq_embedding"`
	EntityID      uint   `gorm:"not null;index:idx_embedding_entity;uniqueIndex:uniq_embedding"`
	Model         string `gorm:"size:50;not null;uniqueIndex:uniq_embedding"`
	Dim           int    `gorm:"default:0"`
	WorkID        *uint
	TranslationID *uint
	Translation   *Translation `gorm:"foreignKey:TranslationID"`
}

// SearchFilters defines the available filters for a search query.
type SearchFilters struct {
	Languages  []string
	Categories []string
	Tags       []string
	Authors    []string
	DateFrom   *time.Time
	DateTo     *time.Time
}

// SearchResults represents the results of a search query.
type SearchResults struct {
	Works        []Work
	Translations []Translation
	Authors      []Author
	Total        int64
}

// Work-related enums and structs, moved from domain/work/entity.go to break import cycle.

type WorkStatus string

const (
	WorkStatusDraft     WorkStatus = "draft"
	WorkStatusPublished WorkStatus = "published"
	WorkStatusArchived  WorkStatus = "archived"
	WorkStatusDeleted   WorkStatus = "deleted"
)

type WorkType string

const (
	WorkTypePoetry     WorkType = "poetry"
	WorkTypeProse      WorkType = "prose"
	WorkTypeDrama      WorkType = "drama"
	WorkTypeEssay      WorkType = "essay"
	WorkTypeNovel      WorkType = "novel"
	WorkTypeShortStory WorkType = "short_story"
	WorkTypeNovella    WorkType = "novella"
	WorkTypePlay       WorkType = "play"
	WorkTypeScript     WorkType = "script"
	WorkTypeOther      WorkType = "other"
)

type Work struct {
	TranslatableModel
	Title         string     `gorm:"size:255;not null"`
	Description   string     `gorm:"type:text"`
	Type          WorkType   `gorm:"size:50;default:'other'"`
	Status        WorkStatus `gorm:"size:50;default:'draft'"`
	PublishedAt   *time.Time
	Translations  []*Translation `gorm:"polymorphic:Translatable"`
	Authors       []*Author      `gorm:"many2many:work_authors"`
	Tags          []*Tag         `gorm:"many2many:work_tags"`
	Categories    []*Category    `gorm:"many2many:work_categories"`
	Copyrights    []*Copyright `gorm:"many2many:work_copyrights;constraint:OnDelete:CASCADE"`
	Monetizations []*Monetization `gorm:"many2many:work_monetizations;constraint:OnDelete:CASCADE"`
}

func (w *Work) BeforeSave(tx *gorm.DB) error {
	if w.Title == "" {
		w.Title = "Untitled Work"
	}
	return nil
}

func (w *Work) GetID() uint                { return w.ID }
func (w *Work) GetType() string            { return "Work" }
func (w *Work) GetDefaultLanguage() string { return w.Language }

type WorkStats struct {
	BaseModel
	Views            int64   `gorm:"default:0"`
	Likes            int64   `gorm:"default:0"`
	Comments         int64   `gorm:"default:0"`
	Bookmarks        int64   `gorm:"default:0"`
	Shares           int64   `gorm:"default:0"`
	TranslationCount int64   `gorm:"default:0"`
	ReadingTime      int     `gorm:"default:0"`
	Complexity       float64 `gorm:"type:decimal(5,2);default:0.0"`
	Sentiment        float64 `gorm:"type:decimal(5,2);default:0.0"`
	WorkID           uint    `gorm:"uniqueIndex;index"`
	Work             *Work   `gorm:"foreignKey:WorkID;constraint:OnUpdate:CASCADE,OnDelete:CASCADE;"`
}

// Add combines the values of another WorkStats into this one.
func (ws *WorkStats) Add(other *WorkStats) {
	if other == nil {
		return
	}
	ws.Views += other.Views
	ws.Likes += other.Likes
	ws.Comments += other.Comments
	ws.Bookmarks += other.Bookmarks
	ws.Shares += other.Shares
	ws.TranslationCount += other.TranslationCount
	ws.ReadingTime += other.ReadingTime
	// Note: Complexity and Sentiment are not additive. We could average them,
	// but for now, we'll just keep the target's values.
}

type WorkSeries struct {
	BaseModel
	WorkID         uint   `gorm:"index;uniqueIndex:uniq_work_series"`
	Work           *Work  `gorm:"foreignKey:WorkID"`
	SeriesID       uint   `gorm:"index;uniqueIndex:uniq_work_series"`
	Series         *Series `gorm:"foreignKey:SeriesID"`
	NumberInSeries int     `gorm:"default:0"`
}

type BookWork struct {
	BaseModel
	BookID uint `gorm:"index;uniqueIndex:uniq_book_work"`
	Book   *Book `gorm:"foreignKey:BookID"`
	WorkID uint `gorm:"index;uniqueIndex:uniq_book_work"`
	Work   *Work `gorm:"foreignKey:WorkID"`
	Order  int   `gorm:"default:0"`
}

type WorkAuthor struct {
	BaseModel
	WorkID   uint `gorm:"index;uniqueIndex:uniq_work_author_role"`
	Work     *Work `gorm:"foreignKey:WorkID"`
	AuthorID uint `gorm:"index;uniqueIndex:uniq_work_author_role"`
	Author   *Author `gorm:"foreignKey:AuthorID"`
	Role     string  `gorm:"size:50;default:'author';uniqueIndex:uniq_work_author_role"`
	Ordinal  int     `gorm:"default:0"`
}

type WorkCopyright struct {
    WorkID      uint `gorm:"primaryKey;index"`
    CopyrightID uint `gorm:"primaryKey;index"`
    CreatedAt   time.Time
}

func (WorkCopyright) TableName() string { return "work_copyrights" }

type WorkMonetization struct {
    WorkID         uint `gorm:"primaryKey;index"`
    MonetizationID uint `gorm:"primaryKey;index"`
    CreatedAt      time.Time
}

func (WorkMonetization) TableName() string { return "work_monetizations" }

type Localization struct {
	BaseModel
	Key      string `gorm:"size:255;not null;uniqueIndex:uniq_localization_key_language"`
	Value    string `gorm:"type:text;not null"`
	Language string `gorm:"size:50;not null;uniqueIndex:uniq_localization_key_language"`
}
type Media struct {
	BaseModel
	URL           string `gorm:"size:512;not null"`
	Type          string `gorm:"size:50;not null"`
	MimeType      string `gorm:"size:100"`
	Size          int64  `gorm:"default:0"`
	Title         string `gorm:"size:255"`
	Description   string `gorm:"type:text"`
	Language      string `gorm:"size:50;not null"`
	AuthorID      *uint
	Author        *Author `gorm:"foreignKey:AuthorID"`
	TranslationID *uint
	Translation   *Translation `gorm:"foreignKey:TranslationID"`
	CountryID     *uint
	Country       *Country `gorm:"foreignKey:CountryID"`
	CityID        *uint
	City          *City `gorm:"foreignKey:CityID"`
}

type Notification struct {
	BaseModel
	Message     string `gorm:"type:text;not null"`
	Type        string `gorm:"size:50"`
	Read        bool   `gorm:"default:false"`
	Language    string `gorm:"size:50;not null"`
	UserID      uint
	User        *User `gorm:"foreignKey:UserID"`
	RelatedID   *uint
	RelatedType string `gorm:"size:50"`
}
type EditorialWorkflow struct {
	BaseModel
	Stage         string `gorm:"size:50;not null"`
	Notes         string `gorm:"type:text"`
	Language      string `gorm:"size:50;not null"`
	WorkID        *uint
	TranslationID *uint
	Translation   *Translation `gorm:"foreignKey:TranslationID"`
	UserID        uint
	User          *User `gorm:"foreignKey:UserID"`
	AssignedToID  *uint
	AssignedTo    *User `gorm:"foreignKey:AssignedToID"`
	DueDate       *time.Time
	CompletedAt   *time.Time
}
type Admin struct {
	BaseModel
	UserID      uint
	User        *User  `gorm:"foreignKey:UserID"`
	Role        string `gorm:"size:50;not null"`
	Permissions JSONB  `gorm:"type:jsonb;default:'{}'"`
}
type Vote struct {
	BaseModel
	Value         int `gorm:"default:0"`
	UserID        uint
	User          *User `gorm:"foreignKey:UserID"`
	WorkID        *uint
	TranslationID *uint
	Translation   *Translation `gorm:"foreignKey:TranslationID"`
	CommentID     *uint
	Comment       *Comment `gorm:"foreignKey:CommentID"`
}
type Contributor struct {
	BaseModel
	Name          string `gorm:"size:100;not null"`
	Role          string `gorm:"size:50"`
	UserID        *uint
	User          *User `gorm:"foreignKey:UserID"`
	WorkID        *uint
	TranslationID *uint
	Translation   *Translation `gorm:"foreignKey:TranslationID"`
}
type InteractionEvent struct {
	BaseModel
	UserID     *uint
	User       *User  `gorm:"foreignKey:UserID"`
	TargetType string `gorm:"size:50;not null"`
	TargetID   uint      `gorm:"not null"`
	Kind       string    `gorm:"size:30;not null"`
	OccurredAt time.Time `gorm:"index"`
}
type HybridEntityWork struct {
	BaseModel
	Name          string `gorm:"size:100;not null"`
	Type          string `gorm:"size:50"`
	WorkID        *uint
	TranslationID *uint
	Translation   *Translation `gorm:"foreignKey:TranslationID"`
}
