package models

import (
	"database/sql"
	"time"

	"github.com/google/uuid"
	"github.com/lib/pq"
	"gorm.io/gorm"
)

// Contest représente un concours musical
type Contest struct {
	ID              uuid.UUID              `json:"id" gorm:"type:uuid;primaryKey"`
	Title           string                 `json:"title" gorm:"not null"`
	Description     string                 `json:"description" gorm:"not null"`
	Type            string                 `json:"type" gorm:"not null;index"`             // remix, production, sound_design, collaboration
	Status          string                 `json:"status" gorm:"not null;default:'draft'"` // draft, active, voting, completed, cancelled
	CreatorID       uuid.UUID              `json:"creator_id" gorm:"type:uuid;not null;index"`
	OriginalTrackID *uuid.UUID             `json:"original_track_id,omitempty" gorm:"type:uuid"`
	Genre           sql.NullString         `json:"genre,omitempty"`
	BPM             sql.NullInt32          `json:"bpm,omitempty"`
	Key             sql.NullString         `json:"key,omitempty"`
	Requirements    pq.StringArray         `json:"requirements" gorm:"type:jsonb"`
	Rules           pq.StringArray         `json:"rules" gorm:"type:jsonb"`
	Timeline        ContestTimeline        `json:"timeline" gorm:"type:jsonb"`
	Prizes          []ContestPrize         `json:"prizes" gorm:"type:jsonb"`
	JudgingCriteria []JudgingCriterion     `json:"judging_criteria" gorm:"type:jsonb"`
	Settings        map[string]interface{} `json:"settings" gorm:"type:jsonb"`
	CoverImage      sql.NullString         `json:"cover_image,omitempty"`
	IsPublic        bool                   `json:"is_public" gorm:"not null;default:true"`
	IsFeatured      bool                   `json:"is_featured" gorm:"not null;default:false"`
	MaxParticipants sql.NullInt32          `json:"max_participants,omitempty"`
	EntryCount      int64                  `json:"entry_count" gorm:"not null;default:0"`
	ViewCount       int64                  `json:"view_count" gorm:"not null;default:0"`
	VoteCount       int64                  `json:"vote_count" gorm:"not null;default:0"`
	CreatedAt       time.Time              `json:"created_at" gorm:"autoCreateTime"`
	UpdatedAt       time.Time              `json:"updated_at" gorm:"autoUpdateTime"`

	// Relations
	Creator       *User            `json:"creator,omitempty"`
	OriginalTrack *SellableContent `json:"original_track,omitempty"`
	Entries       []ContestEntry   `json:"entries,omitempty"`
	Judges        []ContestJudge   `json:"judges,omitempty"`
	Sponsors      []ContestSponsor `json:"sponsors,omitempty"`
}

// ContestTimeline représente la timeline d'un concours
type ContestTimeline struct {
	StartDate           time.Time `json:"start_date"`
	SubmissionDeadline  time.Time `json:"submission_deadline"`
	VotingStart         time.Time `json:"voting_start"`
	VotingEnd           time.Time `json:"voting_end"`
	ResultsAnnouncement time.Time `json:"results_announcement"`
}

// ContestPrize représente un prix dans un concours
type ContestPrize struct {
	Position     int     `json:"position"`
	Prize        string  `json:"prize"`
	Description  string  `json:"description"`
	CashAmount   float64 `json:"cash_amount,omitempty"`
	Currency     string  `json:"currency,omitempty"`
	Badge        string  `json:"badge,omitempty"`
	Distribution string  `json:"distribution,omitempty"`
}

// JudgingCriterion représente un critère de jugement
type JudgingCriterion struct {
	Name        string  `json:"name"`
	Description string  `json:"description"`
	Weight      float64 `json:"weight"`
	MaxScore    int     `json:"max_score"`
}

// ContestEntry représente une participation à un concours
type ContestEntry struct {
	ID          uuid.UUID              `json:"id" gorm:"type:uuid;primaryKey"`
	ContestID   uuid.UUID              `json:"contest_id" gorm:"type:uuid;not null;index"`
	UserID      uuid.UUID              `json:"user_id" gorm:"type:uuid;not null;index"`
	Title       string                 `json:"title" gorm:"not null"`
	Description string                 `json:"description"`
	AudioFile   string                 `json:"audio_file" gorm:"not null"`
	Metadata    map[string]interface{} `json:"metadata" gorm:"type:jsonb"`
	Status      string                 `json:"status" gorm:"not null;default:'submitted'"` // submitted, approved, disqualified, winner
	Position    sql.NullInt32          `json:"position,omitempty"`
	Score       sql.NullFloat64        `json:"score,omitempty"`
	VoteCount   int64                  `json:"vote_count" gorm:"not null;default:0"`
	ViewCount   int64                  `json:"view_count" gorm:"not null;default:0"`
	CreatedAt   time.Time              `json:"created_at" gorm:"autoCreateTime"`
	UpdatedAt   time.Time              `json:"updated_at" gorm:"autoUpdateTime"`

	// Relations
	Contest *Contest      `json:"contest,omitempty"`
	User    *User         `json:"user,omitempty"`
	Votes   []ContestVote `json:"votes,omitempty"`
}

// ContestJudge représente un juge dans un concours
type ContestJudge struct {
	ID          uuid.UUID      `json:"id" gorm:"type:uuid;primaryKey"`
	ContestID   uuid.UUID      `json:"contest_id" gorm:"type:uuid;not null;index"`
	UserID      uuid.UUID      `json:"user_id" gorm:"type:uuid;not null;index"`
	Role        string         `json:"role" gorm:"not null"` // head_judge, expert_judge, community_judge
	Weight      float64        `json:"weight" gorm:"not null;default:1.0"`
	Credentials sql.NullString `json:"credentials,omitempty"`
	IsActive    bool           `json:"is_active" gorm:"not null;default:true"`
	JoinedAt    time.Time      `json:"joined_at" gorm:"autoCreateTime"`
	CreatedAt   time.Time      `json:"created_at" gorm:"autoCreateTime"`
	UpdatedAt   time.Time      `json:"updated_at" gorm:"autoUpdateTime"`

	// Relations
	Contest *Contest `json:"contest,omitempty"`
	User    *User    `json:"user,omitempty"`
}

// ContestVote représente un vote dans un concours
type ContestVote struct {
	ID        uuid.UUID          `json:"id" gorm:"type:uuid;primaryKey"`
	ContestID uuid.UUID          `json:"contest_id" gorm:"type:uuid;not null;index"`
	EntryID   uuid.UUID          `json:"entry_id" gorm:"type:uuid;not null;index"`
	UserID    uuid.UUID          `json:"user_id" gorm:"type:uuid;not null;index"`
	JudgeID   *uuid.UUID         `json:"judge_id,omitempty" gorm:"type:uuid"`
	VoteType  string             `json:"vote_type" gorm:"not null"` // expert, community
	Score     float64            `json:"score" gorm:"not null"`
	Criteria  map[string]float64 `json:"criteria" gorm:"type:jsonb"`
	Comment   sql.NullString     `json:"comment,omitempty"`
	IsValid   bool               `json:"is_valid" gorm:"not null;default:true"`
	CreatedAt time.Time          `json:"created_at" gorm:"autoCreateTime"`

	// Relations
	Contest *Contest      `json:"contest,omitempty"`
	Entry   *ContestEntry `json:"entry,omitempty"`
	User    *User         `json:"user,omitempty"`
	Judge   *ContestJudge `json:"judge,omitempty"`
}

// ContestSponsor représente un sponsor d'un concours
type ContestSponsor struct {
	ID           uuid.UUID      `json:"id" gorm:"type:uuid;primaryKey"`
	ContestID    uuid.UUID      `json:"contest_id" gorm:"type:uuid;not null;index"`
	Name         string         `json:"name" gorm:"not null"`
	Description  sql.NullString `json:"description,omitempty"`
	Logo         sql.NullString `json:"logo,omitempty"`
	Website      sql.NullString `json:"website,omitempty"`
	Contribution float64        `json:"contribution" gorm:"not null"`
	Currency     string         `json:"currency" gorm:"not null;default:'EUR'"`
	Benefits     pq.StringArray `json:"benefits" gorm:"type:jsonb"`
	IsActive     bool           `json:"is_active" gorm:"not null;default:true"`
	CreatedAt    time.Time      `json:"created_at" gorm:"autoCreateTime"`
	UpdatedAt    time.Time      `json:"updated_at" gorm:"autoUpdateTime"`

	// Relations
	Contest *Contest `json:"contest,omitempty"`
}

// ContestStems représente les stems d'un concours (pour remix contests)
type ContestStems struct {
	ID          uuid.UUID `json:"id" gorm:"type:uuid;primaryKey"`
	ContestID   uuid.UUID `json:"contest_id" gorm:"type:uuid;not null;uniqueIndex"`
	VocalsPath  string    `json:"vocals_path" gorm:"not null"`
	DrumsPath   string    `json:"drums_path" gorm:"not null"`
	BassPath    string    `json:"bass_path" gorm:"not null"`
	OtherPath   string    `json:"other_path" gorm:"not null"`
	DownloadURL string    `json:"download_url" gorm:"not null"`
	CreatedAt   time.Time `json:"created_at" gorm:"autoCreateTime"`
	UpdatedAt   time.Time `json:"updated_at" gorm:"autoUpdateTime"`

	// Relations
	Contest *Contest `json:"contest,omitempty"`
}

// ContestAnalytics représente les analytics d'un concours
type ContestAnalytics struct {
	ID                 uuid.UUID `json:"id" gorm:"type:uuid;primaryKey"`
	ContestID          uuid.UUID `json:"contest_id" gorm:"type:uuid;not null;uniqueIndex"`
	TotalEntries       int64     `json:"total_entries" gorm:"not null;default:0"`
	UniqueParticipants int64     `json:"unique_participants" gorm:"not null;default:0"`
	TotalVotes         int64     `json:"total_votes" gorm:"not null;default:0"`
	UniqueVoters       int64     `json:"unique_voters" gorm:"not null;default:0"`
	AverageScore       float64   `json:"average_score" gorm:"not null;default:0"`
	CompletionRate     float64   `json:"completion_rate" gorm:"not null;default:0"`
	EngagementRate     float64   `json:"engagement_rate" gorm:"not null;default:0"`
	SocialShares       int64     `json:"social_shares" gorm:"not null;default:0"`
	Comments           int64     `json:"comments" gorm:"not null;default:0"`
	Countries          int64     `json:"countries" gorm:"not null;default:0"`
	CreatedAt          time.Time `json:"created_at" gorm:"autoCreateTime"`
	UpdatedAt          time.Time `json:"updated_at" gorm:"autoUpdateTime"`

	// Relations
	Contest *Contest `json:"contest,omitempty"`
}

// ContestBadge représente un badge de concours
type ContestBadge struct {
	ID          uuid.UUID     `json:"id" gorm:"type:uuid;primaryKey"`
	ContestID   uuid.UUID     `json:"contest_id" gorm:"type:uuid;not null;index"`
	UserID      uuid.UUID     `json:"user_id" gorm:"type:uuid;not null;index"`
	BadgeType   string        `json:"badge_type" gorm:"not null"` // winner, participant, judge, sponsor
	Position    sql.NullInt32 `json:"position,omitempty"`
	Description string        `json:"description" gorm:"not null"`
	Icon        string        `json:"icon" gorm:"not null"`
	Rarity      string        `json:"rarity" gorm:"not null;default:'common'"` // common, rare, epic, legendary
	CreatedAt   time.Time     `json:"created_at" gorm:"autoCreateTime"`

	// Relations
	Contest *Contest `json:"contest,omitempty"`
	User    *User    `json:"user,omitempty"`
}

// TableName spécifie le nom de la table pour Contest
func (Contest) TableName() string {
	return "contests"
}

// TableName spécifie le nom de la table pour ContestEntry
func (ContestEntry) TableName() string {
	return "contest_entries"
}

// TableName spécifie le nom de la table pour ContestJudge
func (ContestJudge) TableName() string {
	return "contest_judges"
}

// TableName spécifie le nom de la table pour ContestVote
func (ContestVote) TableName() string {
	return "contest_votes"
}

// TableName spécifie le nom de la table pour ContestSponsor
func (ContestSponsor) TableName() string {
	return "contest_sponsors"
}

// TableName spécifie le nom de la table pour ContestStems
func (ContestStems) TableName() string {
	return "contest_stems"
}

// TableName spécifie le nom de la table pour ContestAnalytics
func (ContestAnalytics) TableName() string {
	return "contest_analytics"
}

// TableName spécifie le nom de la table pour ContestBadge
func (ContestBadge) TableName() string {
	return "contest_badges"
}

// BeforeCreate hook GORM pour générer UUID si non défini
func (m *Contest) BeforeCreate(tx *gorm.DB) error {
	if m.ID == uuid.Nil {
		m.ID = uuid.New()
	}
	return nil
}

// BeforeCreate hook GORM pour générer UUID si non défini
func (m *ContestEntry) BeforeCreate(tx *gorm.DB) error {
	if m.ID == uuid.Nil {
		m.ID = uuid.New()
	}
	return nil
}

// BeforeCreate hook GORM pour générer UUID si non défini
func (m *ContestJudge) BeforeCreate(tx *gorm.DB) error {
	if m.ID == uuid.Nil {
		m.ID = uuid.New()
	}
	return nil
}

// BeforeCreate hook GORM pour générer UUID si non défini
func (m *ContestVote) BeforeCreate(tx *gorm.DB) error {
	if m.ID == uuid.Nil {
		m.ID = uuid.New()
	}
	return nil
}

// BeforeCreate hook GORM pour générer UUID si non défini
func (m *ContestSponsor) BeforeCreate(tx *gorm.DB) error {
	if m.ID == uuid.Nil {
		m.ID = uuid.New()
	}
	return nil
}

// BeforeCreate hook GORM pour générer UUID si non défini
func (m *ContestStems) BeforeCreate(tx *gorm.DB) error {
	if m.ID == uuid.Nil {
		m.ID = uuid.New()
	}
	return nil
}

// BeforeCreate hook GORM pour générer UUID si non défini
func (m *ContestAnalytics) BeforeCreate(tx *gorm.DB) error {
	if m.ID == uuid.Nil {
		m.ID = uuid.New()
	}
	return nil
}

// BeforeCreate hook GORM pour générer UUID si non défini
func (m *ContestBadge) BeforeCreate(tx *gorm.DB) error {
	if m.ID == uuid.Nil {
		m.ID = uuid.New()
	}
	return nil
}
