package export

import (
	"encoding/json"
	"fmt"
	"path/filepath"
	"time"

	"github.com/grafana/grafana-plugin-sdk-go/data"
	"github.com/grafana/grafana/pkg/services/sqlstore"
	jsoniter "github.com/json-iterator/go"
)

func exportAnnotations(helper *commitHelper, job *gitExportJob) error {
	return job.sql.WithDbSession(helper.ctx, func(sess *sqlstore.DBSession) error {
		type annoResult struct {
			ID          int64  `xorm:"id"`
			DashboardID int64  `xorm:"dashboard_id"`
			PanelID     int64  `xorm:"panel_id"`
			UserID      int64  `xorm:"user_id"`
			Text        string `xorm:"text"`
			Epoch       int64  `xorm:"epoch"`
			EpochEnd    int64  `xorm:"epoch_end"`
			Created     int64  `xorm:"created"` // not used
			Tags        string `xorm:"tags"`    // JSON Array
		}

		type annoEvent struct {
			PanelID  int64  `json:"panel"`
			Text     string `json:"text"`
			Epoch    int64  `json:"epoch"` // dashboard/start+end is really the UID
			EpochEnd int64  `json:"epoch_end,omitempty"`
			Tags     []string
		}

		rows := make([]*annoResult, 0)

		sess.Table("annotation").
			Where("org_id = ? AND alert_id = 0", helper.orgID).Asc("epoch")

		err := sess.Find(&rows)
		if err != nil {
			return err
		}

		count := len(rows)
		f_ID := data.NewFieldFromFieldType(data.FieldTypeInt64, count)
		f_DashboardID := data.NewFieldFromFieldType(data.FieldTypeInt64, count)
		f_PanelID := data.NewFieldFromFieldType(data.FieldTypeInt64, count)
		f_Epoch := data.NewFieldFromFieldType(data.FieldTypeTime, count)
		f_EpochEnd := data.NewFieldFromFieldType(data.FieldTypeNullableTime, count)
		f_Text := data.NewFieldFromFieldType(data.FieldTypeString, count)
		f_Tags := data.NewFieldFromFieldType(data.FieldTypeJSON, count)

		f_ID.Name = "ID"
		f_DashboardID.Name = "DashboardID"
		f_PanelID.Name = "PanelID"
		f_Epoch.Name = "Epoch"
		f_EpochEnd.Name = "EpochEnd"
		f_Text.Name = "Text"
		f_Tags.Name = "Tags"

		for id, row := range rows {
			f_ID.Set(id, row.ID)
			f_DashboardID.Set(id, row.DashboardID)
			f_PanelID.Set(id, row.PanelID)
			f_Epoch.Set(id, time.UnixMilli(row.Epoch))
			if row.Epoch != row.EpochEnd {
				f_EpochEnd.SetConcrete(id, time.UnixMilli(row.EpochEnd))
			}
			f_Text.Set(id, row.Text)
			f_Tags.Set(id, json.RawMessage(row.Tags))

			// Save a file for each
			event := &annoEvent{
				PanelID: row.PanelID,
				Text:    row.Text,
			}
			err = json.Unmarshal([]byte(row.Tags), &event.Tags)
			if err != nil {
				return err
			}
			fname := fmt.Sprintf("%d", row.Epoch)
			if row.Epoch != row.EpochEnd {
				fname += "-" + fmt.Sprintf("%d", row.EpochEnd)
			}

			err = helper.add(commitOptions{
				body: []commitBody{
					{
						fpath: filepath.Join(helper.orgDir,
							"annotations",
							"dashboard",
							fmt.Sprintf("id-%d", row.DashboardID),
							fname+".json"),
						body: prettyJSON(event),
					},
				},
				when:    time.UnixMilli(row.Epoch),
				comment: fmt.Sprintf("Added annotation (%d)", row.ID),
				userID:  row.UserID,
			})
			if err != nil {
				return err
			}
		}

		if f_ID.Len() > 0 {
			frame := data.NewFrame("", f_ID, f_DashboardID, f_PanelID, f_Epoch, f_EpochEnd, f_Text, f_Tags)
			js, err := jsoniter.ConfigCompatibleWithStandardLibrary.MarshalIndent(frame, "", "  ")
			if err != nil {
				return err
			}

			err = helper.add(commitOptions{
				body: []commitBody{
					{
						fpath: filepath.Join(helper.orgDir, "annotations", "annotations.json"),
						body:  js, // TODO, pretty?
					},
				},
				when:    time.Now(),
				comment: "Exported annotations",
			})
			if err != nil {
				return err
			}
		}
		return err
	})
}
