// Copyright (C) 2023 Marius Schellenberger

package client

import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"time"

	apiclient "git.giftfish.de/ston1th/keyctl/pkg/api/client"
	"git.giftfish.de/ston1th/keyctl/pkg/api/v1/schema"
)

var (
	ErrClientIsNil = errors.New("client is nil")
	keyPath        = schema.KeyPath
	reqPath        = schema.ReqPath
)

type Client struct {
	c *apiclient.Client
}

func NewClient(c *apiclient.Client) (*Client, error) {
	if c == nil {
		return nil, ErrClientIsNil
	}
	return &Client{c}, nil
}

func (c *Client) GetApprovals(ctx context.Context) (approvals schema.Approvals, err error) {
	path := reqPath
	req, err := c.c.NewRequest(ctx, "GET", path, nil)
	if err != nil {
		return
	}
	_, err = c.c.Do(req, &approvals)
	return
}

func (c *Client) RejectApproval(ctx context.Context, id string) error {
	return c.sendApproval(ctx, id, false)
}

func (c *Client) AcceptApproval(ctx context.Context, id string) error {
	return c.sendApproval(ctx, id, true)
}

func (c *Client) sendApproval(ctx context.Context, id string, approve bool) (err error) {
	path := fmt.Sprintf("%s/%s", reqPath, id)
	method := "DELETE"
	if approve {
		method = "PUT"
	}
	req, err := c.c.NewRequest(ctx, method, path, nil)
	if err != nil {
		return
	}
	_, err = c.c.Do(req, nil)
	return
}

func (c *Client) GetKeys(ctx context.Context) (keys schema.Keys, err error) {
	path := keyPath
	req, err := c.c.NewRequest(ctx, "GET", path, nil)
	if err != nil {
		return
	}
	_, err = c.c.Do(req, &keys)
	return
}

func (c *Client) GetKey(ctx context.Context, id string) (key schema.Key, err error) {
	path := fmt.Sprintf("%s/%s", keyPath, id)
	req, err := c.c.NewRequest(ctx, "GET", path, nil)
	if err != nil {
		return
	}
	_, err = c.c.FollowRedirect(req, &key, time.Second*2)
	return
}

func (c *Client) GetKeyLoop(ctx context.Context, id string) (key schema.Key, err error) {
	path := fmt.Sprintf("%s/%s", keyPath, id)
	req, err := c.c.NewRequest(ctx, "GET", path, nil)
	if err != nil {
		return
	}
	_, err = c.c.FollowRedirectLoop(req, &key, time.Second*2)
	return
}

func (c *Client) CreateKey(ctx context.Context, newKey schema.NewKey) (key schema.Key, err error) {
	buf := new(bytes.Buffer)
	path := keyPath
	err = newKey.Validate()
	if err != nil {
		return
	}
	err = json.NewEncoder(buf).Encode(newKey)
	if err != nil {
		return
	}
	req, err := c.c.NewRequest(ctx, "POST", path, buf)
	if err != nil {
		return
	}
	_, err = c.c.Do(req, &key)
	return
}

func (c *Client) DeleteKey(ctx context.Context, id string) (err error) {
	path := fmt.Sprintf("%s/%s", keyPath, id)
	req, err := c.c.NewRequest(ctx, "DELETE", path, nil)
	if err != nil {
		return
	}
	_, err = c.c.Do(req, nil)
	return
}
