package graph

import (
	"context"
	"errors"
	"net/http"
	"strconv"
	"strings"
	"time"

	"github.com/google/uuid"
	"github.com/h2non/bimg"
	log "github.com/sirupsen/logrus"
	"reichard.io/imagini/graph/model"
)

func getContextHTTP(ctx context.Context) (*http.ResponseWriter, *http.Request, error) {
	authContext := ctx.Value("auth").(*model.AuthContext)

	resp := authContext.AuthResponse
	if resp == nil {
		return nil, nil, errors.New("Context Error")
	}

	req := authContext.AuthRequest
	if resp == nil {
		return nil, nil, errors.New("Context Error")
	}

	return resp, req, nil
}

func getContextIDs(ctx context.Context) (string, string, error) {
	authContext := ctx.Value("auth").(*model.AuthContext)
	accessToken := *authContext.AccessToken

	uid, ok := accessToken.Get("sub")
	if !ok {
		return "", "", errors.New("Context Error")
	}

	did, ok := accessToken.Get("did")
	if !ok {
		return "", "", errors.New("Context Error")
	}

	userID, err := uuid.Parse(uid.(string))
	if err != nil {
		return "", "", errors.New("Context Error")
	}

	deviceID, err := uuid.Parse(did.(string))
	if err != nil {
		return "", "", errors.New("Context Error")
	}

	return userID.String(), deviceID.String(), nil
}

func deriveDeviceType(r *http.Request) model.DeviceType {
	userAgent := strings.ToLower(r.Header.Get("User-Agent"))
	if strings.Contains(userAgent, "ios-imagini") {
		return model.DeviceTypeIOs
	} else if strings.Contains(userAgent, "android-imagini") {
		return model.DeviceTypeAndroid
	} else if strings.Contains(userAgent, "chrome") {
		return model.DeviceTypeChrome
	} else if strings.Contains(userAgent, "firefox") {
		return model.DeviceTypeFirefox
	} else if strings.Contains(userAgent, "msie") {
		return model.DeviceTypeInternetExplorer
	} else if strings.Contains(userAgent, "edge") {
		return model.DeviceTypeEdge
	} else if strings.Contains(userAgent, "safari") {
		return model.DeviceTypeSafari
	}
	return model.DeviceTypeUnknown
}

func mediaItemFromEXIF(meta bimg.EXIF) *model.MediaItem {
	mediaItem := &model.MediaItem{}

	// DateTimeOriginal
	formattedTime, _ := time.Parse("2006:01:02 15:04:05", meta.DateTimeOriginal)
	mediaItem.ExifDate = &formattedTime

	// GPSLatitude / Ref
	mediaItem.Latitude = deriveDecimalCoordinate(meta.GPSLatitude, meta.GPSLatitudeRef)

	// GPSLongitude / Ref
	mediaItem.Longitude = deriveDecimalCoordinate(meta.GPSLongitude, meta.GPSLongitudeRef)

	return mediaItem
}

func deriveDecimalCoordinate(coords, direction string) *float64 {
	divideBy := [3]float64{1, 60, 3600}
	var calculatedResult float64

	splitCoords := strings.Split(coords, " ")
	if len(splitCoords) != 3 {
		return nil
	}

	for i := 0; i < len(splitCoords); i++ {
		splitSection := strings.Split(splitCoords[i], "/")
		numerator, err := strconv.ParseFloat(splitSection[0], 64)
		if err != nil {
			return nil
		}
		denominator, err := strconv.ParseFloat(splitSection[1], 64)
		if err != nil {
			return nil
		}
		calculatedResult += numerator / denominator / divideBy[i]
	}

	if direction == "S" {
		calculatedResult *= -1
	} else if direction == "W" {
		calculatedResult *= -1
	}

	log.Info(calculatedResult)
	return &calculatedResult
}
