package main

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"os"
)

type crmFileInfo struct {
	Name string `json:"name"`
	Type string `json:"type"`
	Role string `json:"role"`
	Size int64  `json:"size"`
}

type attachmentID struct {
	ID string `json:"attachmentId"`
}

func crmUploadFile(path string) (fileID string, fileInfo crmFileInfo, err error) {

	fileInfo, err = getFileInfo4CRM(path)
	headers, err := crmPrepareAttachmentHTTPHeader(fileInfo)
	data, err := crmFileDataString(path, fileInfo)
	url := crmUploadAttachmentURL()
	resp, err := postRAW([]byte(data), url, headers)
	fileID, err = crmFileIDFromJSON(resp)
	log.Println(fileID)
	log.Println(err)
	return
}

//crmFileIDFromHTTP  read attachment id from http response
//   as http response cannot be 'rewind', this function is
//   specifically used for one purpose only.
//   i.e. upload attachment to EspoCRM
func crmFileIDFromJSON(jsonStr string) (fileID string, err error) {
	attach := attachmentID{}
	err = json.Unmarshal([]byte(jsonStr), &attach)
	return attach.ID, err
}

//crmPrepareAttachmentHTTPHeader   when uploading a file, we need its mime, auth header, etc.
func crmPrepareAttachmentHTTPHeader(fileInfo crmFileInfo) (headers map[string]string, err error) {
	headers = map[string]string{}
	headers["Authorization"] = crmAuthHeader()
	headers["Accept"] = "application/json"
	headers["Content-Type"] = fileInfo.Type
	return headers, err
}

func crmUploadAttachmentURL() string {

	return CRMConfig.BaseURL + "api/v1/Attachment/action/upload"
}

func crmAuthHeader() string {
	//return "Basic cGF0cmljazpiNjFmYWRlMTM5OWYwY2ZjNmZjZjcxNTU0OTljNTNkOQ=="
	s := CRMConfig.UserName + ":" + CRMConfig.UserPass
	r := base64.StdEncoding.EncodeToString([]byte(s))
	return "Basic " + r
}

//crmFileDataString, encode a base64 string of the given file
//so that the receiver EspoCRM can correctly understand and decode it.
//"data:image/png;base64,iVB....="
//
//TODO: for big files, this might ave issue cause out of memory
func crmFileDataString(path string, fileInfo crmFileInfo) (encoded string, err error) {
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return "", err
	}
	b64content := base64.StdEncoding.EncodeToString(content)
	encoded = fmt.Sprintf("data:%s;base64,%s", fileInfo.Type, b64content)

	//encode it
	return encoded, nil
}

func crmUploadAttachmentMeta(fileID string, fileInfo crmFileInfo) (resp string, err error) {
	headers := map[string]string{}
	headers["Authorization"] = crmAuthHeader()
	headers["Accept"] = "application/json, text/javascript, */*; q=0.01"
	headers["Content-Type"] = "application/json"

	fileInfo.Role = "Attachment"
	jb, _ := json.Marshal(fileInfo)
	log.Println(string(jb))

	URL := crmAttachmentMetaURL(fileID)
	resp, err = putRAW(jb, URL, headers)
	return
}

func crmAttachmentMetaURL(fileID string) string {
	//return "https://c.hitxy.org.au/api/v1/Attachment/" + fileID
	return CRMConfig.BaseURL + "api/v1/Attachment/" + fileID
}

type attachmentInfo struct {
	ID              string `json:"id"`              //"id": "591e55398345683ee",
	Name            string `json:"name"`            //"name": "static_qr_code_without_logo.png",
	Deleted         bool   `json:"deleted"`         //"deleted": false,
	Type            string `json:"type"`            // "type": "image\/png",
	Size            int    `json:"size"`            //"size": 509,
	SourceID        string `json:"sourceId"`        //"sourceId": null,
	CreateAT        string `json:"createAt"`        //"createdAt": "2017-05-19 02:15:21",
	Role            string `json:"role"`            //"role": "Attachment",
	Storage         string `json:"storage"`         //"storage": null,
	StorageFielPath string `json:"storageFilePath"` //"storageFilePath": null,
	Global          bool   `json:"global"`          // "global": false,
	ParentID        string `json:"parentId"`        // "parentId": null,
	ParentType      string `json:"parentType"`      // "parentType": null,
	RelatedID       string `json:"relatedId"`       // "relatedId": null,
	RelatedType     string `json:"relatedType"`     // "relatedType": null,
	CreatedByID     string `json:"createdById"`     // "createdById": "1",
	CreatedbyName   string `json:"createdByName"`   // "createdByName": "Admin"
}

func crmCreateAttachment(path string) (result attachmentInfo, err error) {
	fileID, fileInfo, err := crmUploadFile(path)
	aInfo, err := crmUploadAttachmentMeta(fileID, fileInfo)
	if err != nil {
		return
	}
	json.Unmarshal([]byte(aInfo), &result)
	return
}

func crmDownloadAttachmentAs(fileID, saveAs string) (err error) {

	f, err := crmDownloadAttachment(fileID)
	if err != nil {
		return
	}
	err = os.Rename(f, saveAs)
	return
}

func crmDownloadAttachment(fileID string) (filename string, err error) {
	u := crmURL4DownloadAttachmet(fileID)
	headers := map[string]string{}
	headers["Authorization"] = crmAuthHeader()
	f, _, err := saveURLwithHTTPHeader(u, headers)
	log.Println(f)
	return f, err
}

func crmURL4DownloadAttachmet(fileID string) string {
	return CRMConfig.BaseURL + "?entryPoint=download&id=" + fileID
}
