// SPDX-FileCopyrightText: 2022 Free Mobile
// SPDX-License-Identifier: AGPL-3.0-only

//go:build !release

package metadata

import (
	"context"
	"errors"
	"fmt"
	"strings"
	"testing"

	"akvorado/common/helpers"
	"akvorado/common/reporter"
	"akvorado/common/schema"
	"akvorado/outlet/metadata/provider"
)

// mockProvider represents a mock provider.
type mockProvider struct{}

// Query query the mock provider for a value.
//   - ifIndex = 999 → not found
//   - ifIndex = 998 → transient error
//   - ifIndex = 1010 → with metadata for exporter
//   - ifIndex = 2010 → with metadata for exporter and interface
func (mp mockProvider) Query(_ context.Context, query provider.Query) (provider.Answer, error) {
	ifIndex := query.IfIndex
	if ifIndex == 999 {
		return provider.Answer{}, nil
	}
	if ifIndex == 998 {
		return provider.Answer{}, errors.New("noooo")
	}

	answer := provider.Answer{
		Exporter: provider.Exporter{
			Name: strings.ReplaceAll(query.ExporterIP.Unmap().String(), ".", "_"),
		},
	}
	answer.Interface.Name = fmt.Sprintf("Gi0/0/%d", ifIndex)
	answer.Interface.Description = fmt.Sprintf("Interface %d", ifIndex)
	answer.Interface.Speed = 1000

	// in iface with  metadata (overriden by out iface)
	if ifIndex == 1010 {
		answer.Exporter.Group = "metadata group"
		answer.Exporter.Region = "metadata region"
		answer.Exporter.Role = "metadata role"
		answer.Exporter.Site = "metadata site"
		answer.Exporter.Tenant = "metadata tenant"
	}

	// out iface with metadata
	if ifIndex == 2010 {
		answer.Interface.Boundary = schema.InterfaceBoundaryExternal
		answer.Interface.Connectivity = "metadata connectivity"
		answer.Interface.Provider = "metadata provider"
		answer.Exporter.Group = "metadata group"
		answer.Exporter.Region = "metadata region"
		answer.Exporter.Role = "metadata role"
		answer.Exporter.Site = "metadata site"
		answer.Exporter.Tenant = "metadata tenant"
	}

	answer.Found = true
	return answer, nil
}

// mockProviderConfiguration is the configuration for the mock provider.
type mockProviderConfiguration struct{}

// New returns a new mock provider.
func (mpc mockProviderConfiguration) New(context.Context, *reporter.Reporter) (provider.Provider, error) {
	return mockProvider{}, nil
}

// NewMock creates a new metadata component building synthetic values. It is already started.
func NewMock(t *testing.T, reporter *reporter.Reporter, configuration Configuration, dependencies Dependencies) *Component {
	t.Helper()
	if configuration.Providers == nil {
		configuration.Providers = []ProviderConfiguration{{Config: mockProviderConfiguration{}}}
	}
	c, err := New(reporter, configuration, dependencies)
	if err != nil {
		t.Fatalf("New() error:\n%+v", err)
	}
	helpers.StartStop(t, c)
	return c
}

// emptyProvider represents an empty mock provider.
type emptyProvider struct{}

// Query returns always a not found status for the empty mock provider
func (mp emptyProvider) Query(_ context.Context, _ provider.Query) (provider.Answer, error) {
	return provider.Answer{}, nil
}

// emptyProviderConfiguration is the configuration for the empty provider.
type emptyProviderConfiguration struct{}

// New returns a new empty provider.
func (mpc emptyProviderConfiguration) New(context.Context, *reporter.Reporter) (provider.Provider, error) {
	return emptyProvider{}, nil
}
