package usecase

import (
	"context"
	"fmt"
	"net/http"

	"source.toby3d.me/toby3d/home/internal/domain"
	"source.toby3d.me/toby3d/home/internal/server"
	"source.toby3d.me/toby3d/home/internal/site"
)

type serverUseCase struct {
	sites site.Repository
}

func NewServerUseCase(sites site.Repository) server.UseCase {
	return &serverUseCase{
		sites: sites,
	}
}

func (ucase *serverUseCase) Do(ctx context.Context, lang domain.Language) (*domain.Server, error) {
	site, err := ucase.sites.Get(ctx, domain.LanguageUnd)
	if err != nil {
		return nil, fmt.Errorf("cannot find base site data: %w", err)
	}

	out := domain.NewServer()
	if site.Params == nil {
		return out, nil
	}

	serverMap, ok := site.Params["server"].(map[string]any)
	if !ok {
		return out, nil
	}

	parseHeaders(out, serverMap)
	parseRedirects(out, serverMap)

	return out, nil
}

func parseHeaders(dst *domain.Server, params map[string]any) error {
	serverHeadersValues, ok := params["headers"].([]any)
	if !ok {
		return server.ErrServerHeaders
	}

	for i := range serverHeadersValues {
		headerMap, ok := serverHeadersValues[i].(map[string]any)
		if !ok {
			continue
		}

		header := domain.Header{
			Values: make(map[string]string),
			Path:   "",
		}

		if header.Path, ok = headerMap["path"].(string); !ok {
			continue
		}

		values, ok := headerMap["values"].(map[string]any)
		if !ok {
			continue
		}

		for name, value := range values {
			v, ok := value.(string)
			if !ok {
				continue
			}

			header.Values[name] = v
		}

		dst.Headers = append(dst.Headers, header)
	}

	return nil
}

func parseRedirects(dst *domain.Server, params map[string]any) error {
	serverRedirectsValues, ok := params["redirects"].([]any)
	if !ok {
		return server.ErrServerRedirects
	}

	for i := range serverRedirectsValues {
		redirectMap, ok := serverRedirectsValues[i].(map[string]any)
		if !ok {
			continue
		}

		redirect := domain.Redirect{
			From:   "",
			To:     "",
			Status: http.StatusMovedPermanently,
			Force:  false,
		}

		if redirect.From, ok = redirectMap["from"].(string); !ok {
			continue
		}

		if redirect.To, ok = redirectMap["to"].(string); !ok {
			continue
		}

		if status, ok := redirectMap["status"].(int); ok && status != 0 {
			redirect.Status = status
		}

		redirect.Force, _ = redirectMap["force"].(bool)
		dst.Redirects = append(dst.Redirects, redirect)
	}

	return nil
}
