package freepublish

import (
	"fmt"

	"github.com/silenceper/wechat/v2/officialaccount/context"
	"github.com/silenceper/wechat/v2/util"
)

const (
	publishURL      = "https://api.weixin.qq.com/cgi-bin/freepublish/submit"     // 发布接口
	selectStateURL  = "https://api.weixin.qq.com/cgi-bin/freepublish/get"        // 发布状态轮询接口
	deleteURL       = "https://api.weixin.qq.com/cgi-bin/freepublish/delete"     // 删除发布
	firstArticleURL = "https://api.weixin.qq.com/cgi-bin/freepublish/getarticle" // 通过 article_id 获取已发布文章
	paginateURL     = "https://api.weixin.qq.com/cgi-bin/freepublish/batchget"   // 获取成功发布列表
)

// PublishStatus 发布状态
type PublishStatus uint

const (
	// PublishStatusSuccess 0:成功
	PublishStatusSuccess PublishStatus = iota
	// PublishStatusPublishing 1:发布中
	PublishStatusPublishing
	// PublishStatusOriginalFail 2:原创失败
	PublishStatusOriginalFail
	// PublishStatusFail 3:常规失败
	PublishStatusFail
	// PublishStatusAuditRefused 4:平台审核不通过
	PublishStatusAuditRefused
	// PublishStatusUserDeleted 5:成功后用户删除所有文章
	PublishStatusUserDeleted
	// PublishStatusSystemBanned 6:成功后系统封禁所有文章
	PublishStatusSystemBanned
)

// FreePublish 发布能力
type FreePublish struct {
	*context.Context
}

// NewFreePublish init
func NewFreePublish(ctx *context.Context) *FreePublish {
	return &FreePublish{
		Context: ctx,
	}
}

// Publish 发布接口。需要先将图文素材以草稿的形式保存（见“草稿箱/新建草稿”，
// 如需从已保存的草稿中选择，见“草稿箱/获取草稿列表”），选择要发布的草稿 media_id 进行发布
func (freePublish *FreePublish) Publish(mediaID string) (publishID int64, err error) {
	var accessToken string
	accessToken, err = freePublish.GetAccessToken()
	if err != nil {
		return
	}

	var req struct {
		MediaID string `json:"media_id"`
	}
	req.MediaID = mediaID

	var response []byte
	uri := fmt.Sprintf("%s?access_token=%s", publishURL, accessToken)
	response, err = util.PostJSON(uri, req)
	if err != nil {
		return
	}

	var res struct {
		util.CommonError
		PublishID int64 `json:"publish_id"`
	}
	err = util.DecodeWithError(response, &res, "SubmitFreePublish")
	return res.PublishID, err
}

// PublishStatusList 发布任务状态列表
type PublishStatusList struct {
	util.CommonError
	PublishID     int64                `json:"publish_id"`     // 发布任务id
	PublishStatus PublishStatus        `json:"publish_status"` // 发布状态
	ArticleID     string               `json:"article_id"`     // 当发布状态为0时（即成功）时，返回图文的 article_id，可用于“客服消息”场景
	ArticleDetail PublishArticleDetail `json:"article_detail"` // 发布任务文章成功状态详情
	FailIndex     []uint               `json:"fail_idx"`       // 当发布状态为2或4时，返回不通过的文章编号，第一篇为 1；其他发布状态则为空
}

// PublishArticleDetail 发布任务成功详情
type PublishArticleDetail struct {
	Count uint                 `json:"count"` // 当发布状态为0时（即成功）时，返回文章数量
	Items []PublishArticleItem `json:"item"`
}

// PublishArticleItem 发布任务成功的文章内容
type PublishArticleItem struct {
	Index      uint   `json:"idx"`         // 当发布状态为0时（即成功）时，返回文章对应的编号
	ArticleURL string `json:"article_url"` // 当发布状态为0时（即成功）时，返回图文的永久链接
}

// SelectStatus 发布状态轮询接口
func (freePublish *FreePublish) SelectStatus(publishID int64) (list PublishStatusList, err error) {
	accessToken, err := freePublish.GetAccessToken()
	if err != nil {
		return
	}

	var req struct {
		PublishID int64 `json:"publish_id"`
	}
	req.PublishID = publishID

	var response []byte
	uri := fmt.Sprintf("%s?access_token=%s", selectStateURL, accessToken)
	response, err = util.PostJSON(uri, req)
	if err != nil {
		return
	}

	err = util.DecodeWithError(response, &list, "SelectStatusFreePublish")
	return
}

// Delete 删除发布。
// index 要删除的文章在图文消息中的位置，第一篇编号为1，该字段不填或填0会删除全部文章
// !!!此操作不可逆，请谨慎操作!!!删除后微信公众号后台仍然会有记录!!!
func (freePublish *FreePublish) Delete(articleID string, index uint) (err error) {
	accessToken, err := freePublish.GetAccessToken()
	if err != nil {
		return err
	}

	var req struct {
		ArticleID string `json:"article_id"`
		Index     uint   `json:"index"`
	}
	req.ArticleID = articleID
	req.Index = index

	var response []byte
	uri := fmt.Sprintf("%s?access_token=%s", deleteURL, accessToken)
	response, err = util.PostJSON(uri, req)
	if err != nil {
		return err
	}

	return util.DecodeWithCommonError(response, "DeleteFreePublish")
}

// Article 图文信息内容
type Article struct {
	Title              string `json:"title"`                 // 标题
	Author             string `json:"author"`                // 作者
	Digest             string `json:"digest"`                // 图文消息的摘要，仅有单图文消息才有摘要，多图文此处为空
	Content            string `json:"content"`               // 图文消息的具体内容，支持HTML标签，必须少于2万字符，小于1M，且此处会去除JS
	ContentSourceURL   string `json:"content_source_url"`    // 图文消息的原文地址，即点击“阅读原文”后的URL
	ThumbMediaID       string `json:"thumb_media_id"`        // 图文消息的封面图片素材id（一定是永久MediaID）
	ShowCoverPic       uint   `json:"show_cover_pic"`        // 是否显示封面，0为false，即不显示，1为true，即显示(默认)
	NeedOpenComment    uint   `json:"need_open_comment"`     // 是否打开评论，0不打开(默认)，1打开
	OnlyFansCanComment uint   `json:"only_fans_can_comment"` // 是否粉丝才可评论，0所有人可评论(默认)，1粉丝才可评论
	URL                string `json:"url"`                   // 图文消息的URL
	IsDeleted          bool   `json:"is_deleted"`            // 该图文是否被删除
}

// First 通过 article_id 获取已发布文章
func (freePublish *FreePublish) First(articleID string) (list []Article, err error) {
	accessToken, err := freePublish.GetAccessToken()
	if err != nil {
		return
	}

	var req struct {
		ArticleID string `json:"article_id"`
	}
	req.ArticleID = articleID

	var response []byte
	uri := fmt.Sprintf("%s?access_token=%s", firstArticleURL, accessToken)
	response, err = util.PostJSON(uri, req)
	if err != nil {
		return
	}

	var res struct {
		util.CommonError
		NewsItem []Article `json:"news_item"`
	}
	err = util.DecodeWithError(response, &res, "FirstFreePublish")
	return res.NewsItem, err
}

// ArticleList 发布列表
type ArticleList struct {
	util.CommonError
	TotalCount int64             `json:"total_count"` // 成功发布素材的总数
	ItemCount  int64             `json:"item_count"`  // 本次调用获取的素材的数量
	Item       []ArticleListItem `json:"item"`
}

// ArticleListItem 用于 ArticleList 的 item 节点
type ArticleListItem struct {
	ArticleID  string             `json:"article_id"`  // 成功发布的图文消息id
	Content    ArticleListContent `json:"content"`     // 内容
	UpdateTime int64              `json:"update_time"` // 这篇图文消息素材的最后更新时间
}

// ArticleListContent 用于 ArticleListItem 的 content 节点
type ArticleListContent struct {
	NewsItem []Article `json:"news_item"` // 这篇图文消息素材的内容
}

// Paginate 获取成功发布列表
func (freePublish *FreePublish) Paginate(offset, count int64, noReturnContent bool) (list ArticleList, err error) {
	var accessToken string
	accessToken, err = freePublish.GetAccessToken()
	if err != nil {
		return
	}

	var req struct {
		Count           int64 `json:"count"`
		Offset          int64 `json:"offset"`
		NoReturnContent bool  `json:"no_content"`
	}
	req.Count = count
	req.Offset = offset
	req.NoReturnContent = noReturnContent

	var response []byte
	uri := fmt.Sprintf("%s?access_token=%s", paginateURL, accessToken)
	response, err = util.PostJSON(uri, req)
	if err != nil {
		return
	}

	err = util.DecodeWithError(response, &list, "PaginateFreePublish")
	return
}
