package apiv1

import (
	"fmt"
	"log"
	"net/http"

	"code.secondbit.org/api.hg"
	"code.secondbit.org/ducky/devices.hg"

	"golang.org/x/net/context"
)

type createRequest struct {
	Devices []DeviceChange `json:"devices"`
}

func handleCreateDevices(ctx context.Context, w http.ResponseWriter, r *http.Request) {
	var req createRequest
	var resp Response

	userID, err := api.AuthUser(r)
	if err != nil {
		if err == api.ErrUserIDNotSet {
			api.Encode(w, r, http.StatusUnauthorized, Response{Errors: api.AccessDeniedError})
			return
		}
		api.Encode(w, r, http.StatusForbidden, Response{Errors: api.AccessDeniedError})
		return
	}

	err = api.Decode(r, &req)
	if err != nil {
		api.Encode(w, r, http.StatusBadRequest, Response{Errors: api.InvalidFormatError})
		return
	}

	devicesToCreate := createDevicesFromChanges(req.Devices)
	passedScopes := api.GetScopes(r)
	for pos, device := range devicesToCreate {
		err := validateDeviceCreation(device, passedScopes, userID)
		if err == nil {
			continue
		}
		var requestErr api.RequestError
		switch err {
		case errUnauthorizedLastSeen:
			requestErr.Slug = api.RequestErrAccessDenied
			requestErr.Field = fmt.Sprintf("devices/%d/lastSeen", pos)
		case errUnauthorizedCreated:
			requestErr.Slug = api.RequestErrAccessDenied
			requestErr.Field = fmt.Sprintf("devices/%d/created", pos)
		case errUnauthorizedOwner:
			requestErr.Slug = api.RequestErrAccessDenied
			requestErr.Field = fmt.Sprintf("devices/%d/owner", pos)
		case errInvalidDeviceType:
			requestErr.Slug = api.RequestErrInvalidValue
			requestErr.Field = fmt.Sprintf("devices/%d/type", pos)
		case errDeviceNameTooShort:
			if len(device.Name) == 0 {
				requestErr.Slug = api.RequestErrMissing
			} else {
				requestErr.Slug = api.RequestErrInsufficient
			}
			requestErr.Field = fmt.Sprintf("devices/%d/name", pos)
		case errDeviceNameTooLong:
			requestErr.Slug = api.RequestErrOverflow
			requestErr.Field = fmt.Sprintf("devices/%d/name", pos)
		}
		if requestErr.Slug != "" {
			api.Encode(w, r, http.StatusBadRequest, Response{Errors: []api.RequestError{requestErr}})
			return
		}
		api.Encode(w, r, http.StatusInternalServerError, Response{Errors: api.ActOfGodError})
	}
	createdDevices, err := devices.CreateMany(devicesToCreate, ctx)
	if err != nil {
		// BUG(paddy): we should filter out non-internal errors here and expose better error responses
		log.Printf("Error creating devices: %+v\n", err)
		api.Encode(w, r, http.StatusInternalServerError, Response{Errors: api.ActOfGodError})
		return
	}
	for _, device := range createdDevices {
		resp.Devices = append(resp.Devices, apiDeviceFromCore(device, api.CheckScopes(passedScopes, ScopeViewPushToken.ID)))
	}
	api.Encode(w, r, http.StatusCreated, resp)
}
