// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package storage

import (
	"github.com/apache/dubbo-kubernetes/pkg/bufman/pkg/normalpath"
)

// Mapper is a path mapper.
//
// This will cause a Bucket to operate as if the Mapper has all paths mapped.
type Mapper interface {
	// Map maps the path to the full path.
	//
	// The path is expected to be normalized and validated.
	// The returned path is expected to be normalized and validated.
	// If the path cannot be mapped, this returns false.
	MapPath(path string) (string, bool)
	// Map maps the prefix to the full prefix.
	//
	// The path is expected to be normalized and validated.
	// The returned path is expected to be normalized and validated.
	// If the path cannot be mapped, this returns false.
	MapPrefix(prefix string) (string, bool)
	// UnmapFullPath maps the full path to the path.
	//
	// Returns false if the full path does not apply.
	// The path is expected to be normalized and validated.
	// The returned path is expected to be normalized and validated.
	UnmapFullPath(fullPath string) (string, bool, error)
	isMapper()
}

// MapOnPrefix returns a Mapper that will map the Bucket as if it was created on the given prefix.
//
// The prefix is expected to be normalized and validated.
func MapOnPrefix(prefix string) Mapper {
	return prefixMapper{prefix}
}

// MapChain chains the mappers.
//
// If any mapper does not match, this stops checking Mappers and returns
// an empty path and false. This is as opposed to MatchAnd, that runs
// every Matcher and returns the path regardless.
//
// If the Mappers are empty, a no-op Mapper is returned.
// If there is more than one Mapper, the Mappers are called in order
// for UnmapFullPath, with the order reversed for MapPath and MapPrefix.
//
// That is, order these assuming you are starting with a full path and
// working to a path.
func MapChain(mappers ...Mapper) Mapper {
	switch len(mappers) {
	case 0:
		return nopMapper{}
	case 1:
		return mappers[0]
	default:
		return chainMapper{mappers}
	}
}

// ***** private *****

type prefixMapper struct {
	prefix string
}

func (p prefixMapper) MapPath(path string) (string, bool) {
	return normalpath.Join(p.prefix, path), true
}

func (p prefixMapper) MapPrefix(prefix string) (string, bool) {
	return normalpath.Join(p.prefix, prefix), true
}

func (p prefixMapper) UnmapFullPath(fullPath string) (string, bool, error) {
	if !normalpath.EqualsOrContainsPath(p.prefix, fullPath, normalpath.Relative) {
		return "", false, nil
	}
	path, err := normalpath.Rel(p.prefix, fullPath)
	if err != nil {
		return "", false, err
	}
	return path, true, nil
}

func (prefixMapper) isMapper() {}

type chainMapper struct {
	mappers []Mapper
}

func (c chainMapper) MapPath(path string) (string, bool) {
	return c.mapFunc(path, Mapper.MapPath)
}

func (c chainMapper) MapPrefix(prefix string) (string, bool) {
	return c.mapFunc(prefix, Mapper.MapPrefix)
}

func (c chainMapper) UnmapFullPath(fullPath string) (string, bool, error) {
	path := fullPath
	var matches bool
	var err error
	for _, mapper := range c.mappers {
		path, matches, err = mapper.UnmapFullPath(path)
		if err != nil {
			return "", false, err
		}
		if !matches {
			return "", false, nil
		}
	}
	return path, true, nil
}

func (c chainMapper) mapFunc(
	pathOrPrefix string,
	f func(Mapper, string) (string, bool),
) (string, bool) {
	fullPathOrPrefix := pathOrPrefix
	var matches bool
	for i := len(c.mappers) - 1; i >= 0; i-- {
		mapper := c.mappers[i]
		fullPathOrPrefix, matches = f(mapper, fullPathOrPrefix)
		if !matches {
			return "", false
		}
	}
	return fullPathOrPrefix, true
}

func (chainMapper) isMapper() {}

type nopMapper struct{}

func (n nopMapper) MapPath(path string) (string, bool) {
	return path, true
}

func (n nopMapper) MapPrefix(prefix string) (string, bool) {
	return prefix, true
}

func (nopMapper) UnmapFullPath(fullPath string) (string, bool, error) {
	return fullPath, true, nil
}

func (nopMapper) isMapper() {}
