package middleware

import (
	"bytes"
	"fmt"
	"io"
	cc "rpirelay/internal/context"
	apierr "rpirelay/internal/errors"
	"rpirelay/internal/response"
	"runtime"
	"strings"

	"github.com/pkg/errors"
)

func Initialize(secret string) *Middleware {
	return &Middleware{secret: secret}
}

type Middleware struct {
	secret string
}

func (m *Middleware) APIPanicCatch() cc.CustomHandler {
	return func(c *cc.C) {
		defer func() {
			if err := recover(); err != nil {
				// build error
				// *****
				builder := new(strings.Builder)
				builder.WriteString("[API Error Catch]\n")

				pc := make([]uintptr, 10)
				n := runtime.Callers(1, pc)
				frames := runtime.CallersFrames(pc[:n])

				builder.WriteString("\n[Stack]\n")
				for {
					frame, more := frames.Next()
					builder.WriteString(fmt.Sprintf("%s\n\t%s:%d\n", frame.Func.Name(), frame.File, frame.Line))
					if !more {
						break
					}
				}

				builder.WriteString("\n[Error]\n")
				builder.WriteString(fmt.Sprintf("%v\n", err))

				fmt.Printf("%s\n", builder.String())
				// *****
				var e *apierr.APIError
				if converted, ok := err.(*apierr.APIError); ok {
					e = converted
				} else {
					e = apierr.ErrInternalError
				}

				code := make([]response.MessageCode, 0)
				if c := e.Code(); c != nil {
					code = append(code, *c)
				}
				resp := response.Get(e.Status(), code...)

				c.AbortWithStatusJSON(resp.Status, resp.Body)
			}
		}()

		// 是json body 才做複製
		if c.GetHeader("content-type") == "application/json" {
			data, err := c.GetRawData()
			if err != nil {
				panic(apierr.ErrInternalError.SetErr(err))
			}

			c.Request.Body = io.NopCloser(bytes.NewBuffer(data))
			c.Set("_RawBody", data)
		}

		c.Next()
	}
}

func (m *Middleware) Authorization() cc.CustomHandler {
	return func(c *cc.C) {
		auth := c.GetHeader("x-lawsnote-key")
		if auth == "" {
			panic(apierr.ErrUnauthorized.SetErr(errors.New("no lawsnote header found")))
		}

		if auth != m.secret {
			panic(apierr.ErrForbidden.SetErr(errors.New("secret not match")))
		}

		c.Next()
	}
}
