package ghost

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"time"
)

type GhostAPI struct {
	BaseURL string
	Jar     *cookiejar.Jar
}

func (api *GhostAPI) get(path string, query string) (response *http.Response, err error) {
	requestUrl, err := url.JoinPath(api.BaseURL, path)
	if err != nil {
		return nil, err
	}

	if api.Jar == nil {
		api.Jar, err = cookiejar.New(nil)
		if err != nil {
			return nil, err
		}
	}

	client := http.Client{Jar: api.Jar}

	response, err = client.Get(requestUrl + query)
	if err != nil {
		return response, err
	}

	if response.StatusCode > 299 {
		return response, fmt.Errorf("server returned status %d", response.StatusCode)
	}

	return response, nil
}

func (api *GhostAPI) post(path string, data interface{}) (response *http.Response, err error) {
	requestUrl, err := url.JoinPath(api.BaseURL, path)
	if err != nil {
		return nil, err
	}

	if api.Jar == nil {
		api.Jar, err = cookiejar.New(nil)
		if err != nil {
			return nil, err
		}
	}

	client := http.Client{Jar: api.Jar}

	marshaledData, err := json.Marshal(data)
	if err != nil {
		return nil, err
	}

	dataReader := bytes.NewReader(marshaledData)

	response, err = client.Post(requestUrl, "application/json", dataReader)
	if err != nil {
		return response, err
	}

	if response.StatusCode > 299 {
		return response, fmt.Errorf("server returned status %d", response.StatusCode)
	}

	return response, nil
}

type LoginRequest struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

func (api *GhostAPI) Login(username string, password string) (token string, err error) {
	data := LoginRequest{
		Username: username,
		Password: password,
	}

	response, err := api.post("/api/admin/session/", data)
	if err != nil {
		return "", err
	}

	cookies := response.Cookies()

	for _, cookie := range cookies {
		if cookie.Name != "ghost-admin-api-session" {
			continue
		}

		token = cookie.Value
		break
	}

	return token, nil
}

type UserData struct {
	Users []User `json:"users"`
}

type User struct {
	ID                                   string    `json:"id"`
	Name                                 string    `json:"name"`
	Slug                                 string    `json:"slug"`
	Email                                string    `json:"email"`
	ProfileImage                         string    `json:"profile_image"`
	CoverImage                           string    `json:"cover_image"`
	Bio                                  string    `json:"bio"`
	Website                              string    `json:"website"`
	Location                             string    `json:"location"`
	Facebook                             string    `json:"facebook"`
	Twitter                              string    `json:"twitter"`
	Accessibility                        string    `json:"accessibility"`
	Status                               string    `json:"status"`
	MetaTitle                            string    `json:"meta_title"`
	MetaDescription                      string    `json:"meta_description"`
	Tour                                 string    `json:"tour"`
	LastSeen                             time.Time `json:"last_seen"`
	CommentNotifications                 bool      `json:"comment_notifications"`
	FreeMemberSignupNotification         bool      `json:"free_member_signup_notification"`
	PaidSubscriptionStartedNotification  bool      `json:"paid_subscription_started_notification"`
	PaidSubscriptionCanceledNotification bool      `json:"paid_subscription_canceled_notification"`
	CreatedAt                            time.Time `json:"created_at"`
	UpdatedAt                            time.Time `json:"updated_at"`
	Roles                                []Role    `json:"roles"`
	Url                                  string    `json:"url"`
}

type Role struct {
	ID          string    `json:"id"`
	Name        string    `json:"name"`
	Description string    `json:"description"`
	CreatedAt   time.Time `json:"created_at"`
	UpdatedAt   time.Time `json:"updated_at"`
}

func (api *GhostAPI) UserSelf() (user *UserData, err error) {
	response, err := api.get("/api/admin/users/me", "?include=roles")
	if err != nil {
		return nil, err
	}

	user = &UserData{}

	decoder := json.NewDecoder(response.Body)

	err = decoder.Decode(user)
	if err != nil {
		return nil, err
	}

	return user, nil
}