package models

import (
	"exhibitionCentre/database"
	"exhibitionCentre/logging"
	"time"

	"gorm.io/gorm"
)

type Exhibition struct {
	gorm.Model
	Style               int
	Title               string    `gorm:"type:varchar(256);not null"`
	Subtitle            string    `gorm:"type:varchar(256);not null"`
	StartTime           time.Time `gorm:"not null"`
	EndTime             time.Time `gorm:"not null"`
	Cover               string    `gorm:"not null"`
	FineWork            bool
	Master              bool
	Classification      int `gorm:"not null"`
	Published           bool
	OpeningCeremonyUsed bool
	ExhibitionHallUsed  bool
	StudioUsed          bool
	Likes               int  // 点赞数
	Flowers             int  // 送花数
	Applauses           int  // 鼓掌数
	UserId              uint `gorm:"not null"`
}

type ExhibitionDetail struct {
	ID                  int       `json:"id"`                    // 展览id
	Style               int       `json:"style"`                 // 展览场馆类型
	Title               string    `json:"title"`                 // 展览标题
	Subtitle            string    `json:"subtitle"`              // 展览副标题
	Cover               string    `json:"cover"`                 // 展览封面
	StartTime           time.Time `json:"start_time"`            // 展览开始时间
	EndTime             time.Time `json:"end_time"`              // 展览结束时间
	OpeningCeremonyUsed bool      `json:"opening_ceremony_used"` // 是否使用开幕式
	ExhibitionHallUsed  bool      `json:"exhibition_hall_used"`  // 是否使用展厅
	StudioUsed          bool      `json:"studio_used"`           // 是否使用演播厅
	Likes               int       `json:"likes"`                 // 展览点赞数
	Flowers             int       `json:"flowers"`               // 展览送花数
	Applauses           int       `json:"applauses"`             // 展览鼓掌数
}

func init() {
	if err := database.DB.AutoMigrate(&Exhibition{}); err != nil {
		logging.Log.Fatalf("Mysql初始化Exhibition表失败: %s\n", err.Error())
	}
	logging.Log.Info("Mysql初始化Exhibition表完成.")
}

func CreateExhibition(ex *Exhibition) error {
	if err := database.DB.Create(ex).Error; err != nil {
		return err
	}
	return nil // 成功创建
}

func GetExhibition(id int) (*Exhibition, error) {
	// 获取第一个id为指定id的展览
	var exhibition Exhibition
	if err := database.DB.First(&exhibition, "id = ?", uint(id)).Error; err != nil {
		return nil, err
	}
	return &exhibition, nil
}

func GetAllExhibitionsByUserId(userId uint) ([]Exhibition, error) {
	var exhibitions []Exhibition
	if err := database.DB.Order("id desc").Find(&exhibitions, "user_id = ?", userId).Error; err != nil {
		return exhibitions, err
	}
	return exhibitions, nil
}

/******************************************** 所有展览相关查询 ********************************************/
// 根据展览分类查询展览
func GetExhibitionsByClassification(classification, page, pageSize int) ([]Exhibition, error) {
	var exhibitions []Exhibition
	order := "(case when start_time <= now() and now() < end_time then start_time end) desc," + // 第一步，先排序是否进行中，然后按开始时间大小倒序
		"(case when now() > end_time then end_time end) desc," + // 第二步，再排序是否过期，然后按开始时间大小倒序
		"(case when now() < start_time then start_time end) asc" // 第三步，最后排序将要举办的，开始时间大小升序
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 12
	}
	var db *gorm.DB
	if classification == 0 { // 表示不区分分类，查询所有分类
		if db = database.DB.Model(&Exhibition{}).Where("published = ?", true); db.Error != nil {
			return exhibitions, db.Error
		}
	} else {
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND classification = ?", true, classification); db.Error != nil {
			return exhibitions, db.Error
		}
	}
	var count int64
	db.Count(&count)
	if count <= 0 {
		return exhibitions, nil
	}
	offset := (page - 1) * pageSize
	if offset > int(count)-1 {
		return exhibitions, nil
	}
	if err := db.Order(order).Limit(pageSize).Offset(offset).Find(&exhibitions).Error; err != nil {
		return exhibitions, err
	}
	return exhibitions, nil
}

// 根据展览分类，查询正在进行中的展览
func GetNowExhibitionsByClassification(classification, page, pageSize int) ([]Exhibition, error) {
	var exhibitions []Exhibition
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 12
	}
	now := time.Now()
	var db *gorm.DB
	if classification == 0 { // 表示不区分分类，查询所有分类
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND start_time <= ? AND end_time > ?", true, now, now); db.Error != nil {
			return exhibitions, db.Error
		}
	} else {
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND classification = ? AND start_time <= ? AND end_time > ?", true, classification, now, now); db.Error != nil {
			return exhibitions, db.Error
		}
	}
	var count int64
	db.Count(&count)
	if count <= 0 {
		return exhibitions, nil
	}
	offset := (page - 1) * pageSize
	if offset > int(count)-1 {
		return exhibitions, nil
	}
	if err := db.Order("start_time desc").Limit(pageSize).Offset(offset).Find(&exhibitions).Error; err != nil {
		return exhibitions, err
	}
	return exhibitions, nil
}

// 根据展览分类查询过期的展览
func GetPastExhibitionsByClassification(classification, page, pageSize int) ([]Exhibition, error) {
	var exhibitions []Exhibition
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 12
	}
	now := time.Now()
	var db *gorm.DB
	if classification == 0 { // 表示不区分分类，查询所有分类
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND end_time < ?", true, now); db.Error != nil {
			return exhibitions, db.Error
		}
	} else {
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND classification = ? AND end_time < ?", true, classification, now); db.Error != nil {
			return exhibitions, db.Error
		}
	}
	var count int64
	db.Count(&count)
	if count <= 0 {
		return exhibitions, nil
	}
	offset := (page - 1) * pageSize
	if offset > int(count)-1 {
		return exhibitions, nil
	}
	if err := db.Order("end_time desc").Limit(pageSize).Offset(offset).Find(&exhibitions).Error; err != nil {
		return exhibitions, err
	}
	return exhibitions, nil
}

// 根据展览分类查询将来开启的展览
func GetFutureExhibitionsByClassification(classification, page, pageSize int) ([]Exhibition, error) {
	var exhibitions []Exhibition
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 12
	}
	now := time.Now()
	var db *gorm.DB
	if classification == 0 { // 表示不区分分类，查询所有分类
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND start_time > ?", true, now); db.Error != nil {
			return exhibitions, db.Error
		}
	} else {
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND classification = ? AND start_time > ?", true, classification, now); db.Error != nil {
			return exhibitions, db.Error
		}
	}
	var count int64
	db.Count(&count)
	if count <= 0 {
		return exhibitions, nil
	}
	offset := (page - 1) * pageSize
	if offset > int(count)-1 {
		return exhibitions, nil
	}
	if err := db.Order("start_time asc").Limit(pageSize).Offset(offset).Find(&exhibitions).Error; err != nil {
		return exhibitions, err
	}
	return exhibitions, nil
}

/******************************************** 精品展览相关查询 ********************************************/
// 根据展览分类、精品标签，查询展览
func GetExhibitionsByClassificationAndFineWork(classification, page, pageSize int) ([]Exhibition, error) {
	var exhibitions []Exhibition
	order := "(case when start_time <= now() and now() < end_time then start_time end) desc," + // 第一步，先排序是否进行中，然后按开始时间大小倒序
		"(case when now() > end_time then end_time end) desc," + // 第二步，再排序是否过期，然后按开始时间大小倒序
		"(case when now() < start_time then start_time end) asc" // 第三步，最后排序将要举办的，开始时间大小升序
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 12
	}
	var db *gorm.DB
	if classification == 0 { // 表示不区分分类，查询所有分类
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND fine_work = ?", true, true); db.Error != nil {
			return exhibitions, db.Error
		}
	} else {
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND fine_work = ? AND classification = ?", true, true, classification); db.Error != nil {
			return exhibitions, db.Error
		}
	}
	var count int64
	db.Count(&count)
	if count <= 0 {
		return exhibitions, nil
	}
	offset := (page - 1) * pageSize
	if offset > int(count)-1 {
		return exhibitions, nil
	}
	if err := db.Order(order).Limit(pageSize).Offset(offset).Find(&exhibitions).Error; err != nil {
		return exhibitions, err
	}
	return exhibitions, nil
}

// 根据展览分类、精品标签，查询正在进行中的展览
func GetNowExhibitionsByClassificationAndFineWork(classification, page, pageSize int) ([]Exhibition, error) {
	var exhibitions []Exhibition
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 12
	}
	now := time.Now()
	var db *gorm.DB
	if classification == 0 { // 表示不区分分类，查询所有分类
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND fine_work = ? AND start_time <= ? AND end_time > ?", true, true, now, now); db.Error != nil {
			return exhibitions, db.Error
		}
	} else {
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND fine_work = ? AND classification = ? AND start_time <= ? AND end_time > ?", true, true, classification, now, now); db.Error != nil {
			return exhibitions, db.Error
		}
	}
	var count int64
	db.Count(&count)
	if count <= 0 {
		return exhibitions, nil
	}
	offset := (page - 1) * pageSize
	if offset > int(count)-1 {
		return exhibitions, nil
	}
	if err := db.Order("start_time desc").Limit(pageSize).Offset(offset).Find(&exhibitions).Error; err != nil {
		return exhibitions, err
	}
	return exhibitions, nil
}

// 根据展览分类、精品标签，查询过期的展览
func GetPastExhibitionsByClassificationAndFineWork(classification, page, pageSize int) ([]Exhibition, error) {
	var exhibitions []Exhibition
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 12
	}
	now := time.Now()
	var db *gorm.DB
	if classification == 0 { // 表示不区分分类，查询所有分类
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND fine_work = ? AND end_time < ?", true, true, now); db.Error != nil {
			return exhibitions, db.Error
		}
	} else {
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND fine_work = ? AND classification = ? AND end_time < ?", true, true, classification, now); db.Error != nil {
			return exhibitions, db.Error
		}
	}
	var count int64
	db.Count(&count)
	if count <= 0 {
		return exhibitions, nil
	}
	offset := (page - 1) * pageSize
	if offset > int(count)-1 {
		return exhibitions, nil
	}
	if err := db.Order("end_time desc").Limit(pageSize).Offset(offset).Find(&exhibitions).Error; err != nil {
		return exhibitions, err
	}
	return exhibitions, nil
}

// 根据展览分类、精品标签，查询将来开启的展览
func GetFutureExhibitionsByClassificationAndFineWork(classification, page, pageSize int) ([]Exhibition, error) {
	var exhibitions []Exhibition
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 12
	}
	now := time.Now()
	var db *gorm.DB
	if classification == 0 { // 表示不区分分类，查询所有分类
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND fine_work = ? AND start_time > ?", true, true, now); db.Error != nil {
			return exhibitions, db.Error
		}
	} else {
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND fine_work = ? AND classification = ? AND start_time > ?", true, true, classification, now); db.Error != nil {
			return exhibitions, db.Error
		}
	}
	var count int64
	db.Count(&count)
	if count <= 0 {
		return exhibitions, nil
	}
	offset := (page - 1) * pageSize
	if offset > int(count)-1 {
		return exhibitions, nil
	}
	if err := db.Order("start_time asc").Limit(pageSize).Offset(offset).Find(&exhibitions).Error; err != nil {
		return exhibitions, err
	}
	return exhibitions, nil
}

/******************************************** 名家展览相关查询 ********************************************/
// 根据展览分类、名家标签，查询展览
func GetExhibitionsByClassificationAndMaster(classification, page, pageSize int) ([]Exhibition, error) {
	var exhibitions []Exhibition
	order := "(case when start_time <= now() and now() < end_time then start_time end) desc," + // 第一步，先排序是否进行中，然后按开始时间大小倒序
		"(case when now() > end_time then end_time end) desc," + // 第二步，再排序是否过期，然后按开始时间大小倒序
		"(case when now() < start_time then start_time end) asc" // 第三步，最后排序将要举办的，开始时间大小升序
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 12
	}
	var db *gorm.DB
	if classification == 0 { // 表示不区分分类，查询所有分类
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND master = ?", true, true); db.Error != nil {
			return exhibitions, db.Error
		}
	} else {
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND master = ? AND classification = ?", true, true, classification); db.Error != nil {
			return exhibitions, db.Error
		}
	}
	var count int64
	db.Count(&count)
	if count <= 0 {
		return exhibitions, nil
	}
	offset := (page - 1) * pageSize
	if offset > int(count)-1 {
		return exhibitions, nil
	}
	if err := db.Order(order).Limit(pageSize).Offset(offset).Find(&exhibitions).Error; err != nil {
		return exhibitions, err
	}
	return exhibitions, nil
}

// 根据展览分类、名家标签，查询正在进行中的展览
func GetNowExhibitionsByClassificationAndMaster(classification, page, pageSize int) ([]Exhibition, error) {
	var exhibitions []Exhibition
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 12
	}
	now := time.Now()
	var db *gorm.DB
	if classification == 0 { // 表示不区分分类，查询所有分类
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND master = ? AND start_time <= ? AND end_time > ?", true, true, now, now); db.Error != nil {
			return exhibitions, db.Error
		}
	} else {
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND master = ? AND classification = ? AND start_time <= ? AND end_time > ?", true, true, classification, now, now); db.Error != nil {
			return exhibitions, db.Error
		}
	}
	var count int64
	db.Count(&count)
	if count <= 0 {
		return exhibitions, nil
	}
	offset := (page - 1) * pageSize
	if offset > int(count)-1 {
		return exhibitions, nil
	}
	if err := db.Order("start_time desc").Limit(pageSize).Offset(offset).Find(&exhibitions).Error; err != nil {
		return exhibitions, err
	}
	return exhibitions, nil
}

// 根据展览分类、名家标签，查询过期的展览
func GetPastExhibitionsByClassificationAndMaster(classification, page, pageSize int) ([]Exhibition, error) {
	var exhibitions []Exhibition
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 12
	}
	now := time.Now()
	var db *gorm.DB
	if classification == 0 { // 表示不区分分类，查询所有分类
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND master = ? AND end_time < ?", true, true, now); db.Error != nil {
			return exhibitions, db.Error
		}
	} else {
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND master = ? AND classification = ? AND end_time < ?", true, true, classification, now); db.Error != nil {
			return exhibitions, db.Error
		}
	}
	var count int64
	db.Count(&count)
	if count <= 0 {
		return exhibitions, nil
	}
	offset := (page - 1) * pageSize
	if offset > int(count)-1 {
		return exhibitions, nil
	}
	if err := db.Order("end_time desc").Limit(pageSize).Offset(offset).Find(&exhibitions).Error; err != nil {
		return exhibitions, err
	}
	return exhibitions, nil
}

// 根据展览分类、名家标签，查询将来开启的展览
func GetFutureExhibitionsByClassificationAndMaster(classification, page, pageSize int) ([]Exhibition, error) {
	var exhibitions []Exhibition
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = 12
	}
	now := time.Now()
	var db *gorm.DB
	if classification == 0 { // 表示不区分分类，查询所有分类
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND master = ? AND start_time > ?", true, true, now); db.Error != nil {
			return exhibitions, db.Error
		}
	} else {
		if db = database.DB.Model(&Exhibition{}).Where("published = ? AND master = ? AND classification = ? AND start_time > ?", true, true, classification, now); db.Error != nil {
			return exhibitions, db.Error
		}
	}
	var count int64
	db.Count(&count)
	if count <= 0 {
		return exhibitions, nil
	}
	offset := (page - 1) * pageSize
	if offset > int(count)-1 {
		return exhibitions, nil
	}
	if err := db.Order("start_time asc").Limit(pageSize).Offset(offset).Find(&exhibitions).Error; err != nil {
		return exhibitions, err
	}
	return exhibitions, nil
}

func UpdateExhibition(exhibition *Exhibition) error {
	if err := database.DB.Save(exhibition).Error; err != nil {
		return err
	}
	return nil
}

func DeleteExhibition(id int) error {
	if err := database.DB.Delete(&Exhibition{}, "id = ?", id).Error; err != nil {
		return err
	}
	return nil
}
