package model

import (
	"crawler/config"
	"crawler/service"
	"database/sql"
	"encoding/json"
	"fmt"
	"strconv"
)

type MovieInfoModel struct {
	SearchMovieInfoParams
	SearchMovieInfo
	MovieInfo
	Nations
	Genres
	Directors
	Actors
	ShowTypes
	Companys
	Audits
	Staffs
}

// 일별 박스오피스 검색 변수
type SearchMovieInfoParams struct {
	Key     string `form:"key" url:"key" binding:"required"`
	MovieCd string `form:"movieCd" url:"movieCd" binding:"required"`
}

type SearchMovieInfo struct {
	MovieInfoResult struct {
		Source    string    `json:"source"`
		MovieInfo MovieInfo `json:"movieInfo"`
	} `json:"movieInfoResult"`
}

type MovieInfo struct {
	MovieCd    string      `json:"movieCd"`
	MovieNm    string      `json:"movieNm"`
	MovieNmEn  string      `json:"movieNmEn"`
	MovieNmOg  string      `json:"movieNmOg"`
	ShowTm     string      `json:"showTm"`
	PrdtYear   string      `json:"prdtYear"`
	OpenDt     string      `json:"openDt"`
	PrdtStatNm string      `json:"prdtStatNm"`
	TypeNm     string      `json:"typeNm"`
	Nations    []Nations   `json:"nations"`
	Genres     []Genres    `json:"genres"`
	Directors  []Directors `json:"directors"`
	Actors     []Actors    `json:"actors"`
	ShowTypes  []ShowTypes `json:"showTypes"`
	Companys   []Companys  `json:"companys"`
	Audits     []Audits    `json:"audits"`
	Staffs     []Staffs    `json:"staffs"`
}

type Nations struct {
	NationNm string `json:"nationNm"`
}

type Genres struct {
	GenreNm string `json:"genreNm"`
}

type Directors struct {
	PeopleNm   string `json:"peopleNm"`
	PeopleNmEn string `json:"peopleNmEn"`
}

type Actors struct {
	PeopleNm   string `json:"peopleNm"`
	PeopleNmEn string `json:"peopleNmEn"`
	Cast       string `json:"cast"`
	CastEn     string `json:"castEn"`
}

type ShowTypes struct {
	ShowTypeGroupNm string `json:"showTypeGroupNm"`
	ShowTypeNm      string `json:"showTypeNm"`
}

type Companys struct {
	CompanyCd     string `json:"companyCd"`
	CompanyNm     string `json:"companyNm"`
	CompanyNmEn   string `json:"companyNmEn"`
	CompanyPartNm string `json:"companyPartNm"`
}

type Audits struct {
	AuditNo      string `json:"auditNo"`
	WatchGradeNm string `json:"watchGradeNm"`
}

type Staffs struct {
	PeopleNm    string `json:"peopleNm"`
	PeopleNmEn  string `json:"peopleNmEn"`
	StaffRoleNm string `json:"staffRoleNm"`
}

type MovieInfoTable struct {
	InfoID     int
	MovieCd    string
	MovieNm    *string
	MovieNmEn  *string
	MovieNmOg  *string
	PrdtYear   *int
	ShowTm     *int
	OpenDt     *int
	PrdtStatNm *string
	TypeNm     *string
	Nations    *string
	Genres     *string
	Directors  *string
	Actors     *string
	ShowTypes  *string
	Companys   *string
	Audits     *string
	Staffs     *string
	UpdatedAt  *string
	CreatedAt  string
}

func (this *MovieInfoModel) Insert(row MovieInfo) error {
	var (
		db    = service.DB_MOVIEW
		conn  = db.SQLDB
		query = `
			INSERT INTO tb_movie_info (
				movie_cd, movie_nm, movie_nm_en, movie_nm_og, prdt_year, 
			    show_tm, open_dt, prdt_stat_nm, type_nm, nations, 
			    genres, directors, actors, show_types, companys, 
			   	audits, staffs, updated_at, created_at
			)
			VALUES 
				(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NULL, NOW())
			ON DUPLICATE KEY UPDATE 
			    movie_nm = VALUES(movie_nm), movie_nm_en = VALUES(movie_nm_en), movie_nm_og = VALUES(movie_nm_og), 
			    prdt_year = VALUES(prdt_year), show_tm = VALUES(show_tm), open_dt = VALUES(open_dt), 
			    prdt_stat_nm = VALUES(prdt_stat_nm), type_nm = VALUES(type_nm), nations = VALUES(nations), 
				genres = VALUES(genres), directors = VALUES(directors), actors = VALUES(actors), 
				show_types = VALUES(show_types), companys = VALUES(companys), audits = VALUES(audits), 
				staffs = VALUES(staffs), updated_at = NOW();
		`
		data = this.DataFilter(row)
	)

	_, err := conn.Exec(query,
		data.MovieCd, data.MovieNm, data.MovieNmEn, data.MovieNmOg,
		data.PrdtYear, data.ShowTm, data.OpenDt, data.PrdtStatNm, data.TypeNm,
		data.Nations, data.Genres, data.Directors, data.Actors, data.ShowTypes, data.Companys,
		data.Audits, data.Staffs)
	if err != nil {
		db.SetErrorLog(err, query)
		fmt.Println(err)
		return err
	}

	db.SetGeneralLog(config.GL_ACTION_WRITE, query, "insert movie info")
	return nil
}

func (this *MovieInfoModel) IsExists(movieCd string) bool {
	var (
		db     = service.DB_MOVIEW
		conn   = db.SQLDB
		query  = "SELECT IF(COUNT(*) <= 0, 0, 1) AS `exists` FROM tb_movie_info WHERE movie_cd = ?;"
		exists = false
	)

	err := conn.QueryRow(query, movieCd).Scan(&exists)
	if err != nil {
		db.SetErrorLog(err, query)
		return exists
	}

	db.SetGeneralLog(config.GL_ACTION_SELECT, query, "select exists movie info")
	return exists
}

func (this *MovieInfoModel) Update(row MovieInfo) error {
	var (
		db    = service.DB_MOVIEW
		conn  = db.SQLDB
		query = `
			UPDATE tb_movie_info SET 
				movie_nm = ?, movie_nm_en = ?, movie_nm_og = ?, prdt_year = ?, 
			    show_tm = ?, open_dt = ?, prdt_stat_nm = ?, type_nm = ?, nations = ?, 
			    genres = ?, directors = ?, actors = ?, show_types = ?, companys = ?, 
			   	audits = ?, staffs = ?, updated_at = NOW()
			WHERE movie_cd = ?;
		`
		data = this.DataFilter(row)
	)

	_, err := conn.Exec(query,
		data.MovieNm, data.MovieNmEn, data.MovieNmOg,
		data.PrdtYear, data.ShowTm, data.OpenDt, data.PrdtStatNm, data.TypeNm,
		data.Nations, data.Genres, data.Directors, data.Actors, data.ShowTypes, data.Companys,
		data.Audits, data.Staffs, data.MovieCd)
	if err != nil {
		db.SetErrorLog(err, query)
		return err
	}

	db.SetGeneralLog(config.GL_ACTION_MODIFY, query, "update movie info")
	return nil
}

func (this *MovieInfoModel) DataFilter(row MovieInfo) MovieInfoTable {
	var result MovieInfoTable
	result.MovieCd = row.MovieCd

	if row.MovieNm != "" {
		result.MovieNm = &row.MovieNm
	} else {
		result.MovieNm = nil
	}

	if row.MovieNmEn != "" {
		result.MovieNmEn = &row.MovieNmEn
	} else {
		result.MovieNmEn = nil
	}

	if row.MovieNmOg != "" {
		result.MovieNmOg = &row.MovieNmOg
	} else {
		result.MovieNmOg = nil
	}

	if row.PrdtYear != "" {
		prdtYear, _ := strconv.Atoi(row.PrdtYear)
		result.PrdtYear = &prdtYear
	} else {
		result.PrdtYear = nil
	}

	if row.ShowTm != "" {
		showTm, _ := strconv.Atoi(row.ShowTm)
		result.ShowTm = &showTm
	} else {
		result.ShowTm = nil
	}

	if row.OpenDt != "" {
		openDt, _ := strconv.Atoi(row.OpenDt)
		result.OpenDt = &openDt
	} else {
		result.OpenDt = nil
	}

	if row.PrdtStatNm != "" {
		result.PrdtStatNm = &row.PrdtStatNm
	} else {
		result.PrdtStatNm = nil
	}

	if row.TypeNm != "" {
		result.TypeNm = &row.TypeNm
	} else {
		result.TypeNm = nil
	}

	if len(row.Nations) > 0 {
		nations, _ := json.Marshal(row.Nations)
		s := string(nations)
		result.Nations = &s
	} else {
		result.Nations = nil
	}

	if len(row.Genres) > 0 {
		genres, _ := json.Marshal(row.Genres)
		s := string(genres)
		result.Genres = &s
	} else {
		result.Genres = nil
	}

	if len(row.Directors) > 0 {
		directors, _ := json.Marshal(row.Directors)
		s := string(directors)
		result.Directors = &s
	} else {
		result.Directors = nil
	}

	if len(row.Actors) > 0 {
		actors, _ := json.Marshal(row.Actors)
		s := string(actors)
		result.Actors = &s
	} else {
		result.Actors = nil
	}

	if len(row.ShowTypes) > 0 {
		showtypes, _ := json.Marshal(row.ShowTypes)
		s := string(showtypes)
		result.ShowTypes = &s
	} else {
		result.ShowTypes = nil
	}

	if len(row.Companys) > 0 {
		companys, _ := json.Marshal(row.Companys)
		s := string(companys)
		result.Companys = &s
	} else {
		result.Companys = nil
	}

	if len(row.Audits) > 0 {
		audits, _ := json.Marshal(row.Audits)
		s := string(audits)
		result.Audits = &s
	} else {
		result.Audits = nil
	}

	if len(row.Staffs) > 0 {
		staffs, _ := json.Marshal(row.Staffs)
		s := string(staffs)
		result.Staffs = &s
	} else {
		result.Staffs = nil
	}

	return result
}

func (this *MovieInfoModel) Info(movieCd string) (MovieInfoTable, error) {
	var (
		db    = service.DB_MOVIEW
		conn  = db.SQLDB
		query = "SELECT * FROM tb_movie_info WHERE movie_cd = ? LIMIT 1;"
		info  MovieInfoTable
	)

	err := conn.QueryRow(query, movieCd).Scan(
		&info.InfoID, &info.MovieCd, &info.MovieNm,
		&info.MovieNmEn, &info.MovieNmOg, &info.PrdtYear,
		&info.ShowTm, &info.OpenDt, &info.PrdtStatNm,
		&info.TypeNm, &info.Nations, &info.Genres,
		&info.Directors, &info.Actors, &info.ShowTypes,
		&info.Companys, &info.Audits, &info.Staffs,
		&info.UpdatedAt, &info.CreatedAt,
	)

	if err != nil && err != sql.ErrNoRows {
		db.SetErrorLog(err, query)
		return info, err
	}

	db.SetGeneralLog(config.GL_ACTION_SELECT, query, "select movie info")
	return info, nil
}
