// 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 bandeps

import (
	"context"
	"sync"
)

import (
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/codes"
	"go.opentelemetry.io/otel/trace"

	"go.uber.org/zap"
)

import (
	"github.com/apache/dubbo-kubernetes/pkg/bufman/pkg/app"
	"github.com/apache/dubbo-kubernetes/pkg/bufman/pkg/command"
	"github.com/apache/dubbo-kubernetes/pkg/bufman/pkg/stringutil"
)

type state struct {
	logger            *zap.Logger
	envStdioContainer app.EnvStdioContainer
	runner            command.Runner
	violationMap      map[string]Violation
	// map from ./foo/bar/... to actual packages
	packageExpressionToPackages     map[string]*packagesResult
	packageExpressionToPackagesLock *keyRWLock
	// map from packages to dependencies
	packageToDeps     map[string]*depsResult
	packageToDepsLock *keyRWLock
	lock              sync.RWMutex
	calls             int
	cacheHits         int
	tracer            trace.Tracer
}

func newState(
	logger *zap.Logger,
	envStdioContainer app.EnvStdioContainer,
	runner command.Runner,
) *state {
	return &state{
		logger:                          logger,
		envStdioContainer:               envStdioContainer,
		runner:                          runner,
		violationMap:                    make(map[string]Violation),
		packageExpressionToPackages:     make(map[string]*packagesResult),
		packageExpressionToPackagesLock: newKeyRWLock(),
		packageToDeps:                   make(map[string]*depsResult),
		packageToDepsLock:               newKeyRWLock(),
		tracer:                          otel.GetTracerProvider().Tracer(tracerName),
	}
}

func (s *state) PackagesForPackageExpressions(
	ctx context.Context,
	packageExpressions ...string,
) (map[string]struct{}, error) {
	packages := make(map[string]struct{})
	for _, packageExpression := range packageExpressions {
		iPackages, err := s.packagesForPackageExpression(ctx, packageExpression)
		if err != nil {
			return nil, err
		}
		addMaps(packages, iPackages)
	}
	return packages, nil
}

func (s *state) DepsForPackages(
	ctx context.Context,
	pkgs ...string,
) (map[string]struct{}, error) {
	deps := make(map[string]struct{})
	for _, pkg := range pkgs {
		iDeps, err := s.depsForPackage(ctx, pkg)
		if err != nil {
			return nil, err
		}
		addMaps(deps, iDeps)
	}
	return deps, nil
}

func (s *state) AddViolation(violation Violation) {
	violationKey := violation.key()
	s.lock.Lock()
	if _, ok := s.violationMap[violationKey]; !ok {
		s.violationMap[violationKey] = violation
	}
	s.lock.Unlock()
}

func (s *state) Violations() []Violation {
	s.lock.RLock()
	violations := make([]Violation, 0, len(s.violationMap))
	for _, violation := range s.violationMap {
		violations = append(violations, violation)
	}
	s.lock.RUnlock()
	sortViolations(violations)
	return violations
}

func (s *state) packagesForPackageExpression(
	ctx context.Context,
	packageExpression string,
) (map[string]struct{}, error) {
	defer func() {
		// not worrying about locks
		s.logger.Sugar().Debug("cache", zap.Int("calls", s.calls), zap.Int("hits", s.cacheHits))
	}()

	s.packageExpressionToPackagesLock.RLock(packageExpression)
	s.lock.RLock()
	packageResult, ok := s.packageExpressionToPackages[packageExpression]
	s.lock.RUnlock()
	s.packageExpressionToPackagesLock.RUnlock(packageExpression)
	if ok {
		s.lock.Lock()
		s.calls++
		s.cacheHits++
		s.lock.Unlock()
		return packageResult.Packages, packageResult.Err
	}

	s.packageExpressionToPackagesLock.Lock(packageExpression)
	defer s.packageExpressionToPackagesLock.Unlock(packageExpression)

	s.lock.RLock()
	packageResult, ok = s.packageExpressionToPackages[packageExpression]
	s.lock.RUnlock()
	if ok {
		s.lock.Lock()
		s.calls++
		s.cacheHits++
		s.lock.Unlock()
		return packageResult.Packages, packageResult.Err
	}
	packages, err := s.packagesForPackageExpressionUncached(ctx, packageExpression)
	// we always hold key lock and then this lock so lock ordering is ok
	s.lock.Lock()
	s.packageExpressionToPackages[packageExpression] = newPackagesResult(packages, err)
	s.calls++
	s.lock.Unlock()
	return packages, err
}

func (s *state) packagesForPackageExpressionUncached(
	ctx context.Context,
	packageExpression string,
) (map[string]struct{}, error) {
	ctx, span := s.tracer.Start(ctx, "packagesForPackageExpressionUncached", trace.WithAttributes(
		attribute.Key("packageExpression").String(packageExpression),
	))
	defer span.End()

	data, err := command.RunStdout(ctx, s.envStdioContainer, s.runner, `go`, `list`, packageExpression)
	if err != nil {
		span.RecordError(err)
		span.SetStatus(codes.Error, err.Error())
		return nil, err
	}
	return stringutil.SliceToMap(getNonEmptyLines(string(data))), nil
}

func (s *state) depsForPackage(
	ctx context.Context,
	pkg string,
) (map[string]struct{}, error) {
	defer func() {
		// not worrying about locks
		s.logger.Sugar().Debug("cache", zap.Int("calls", s.calls), zap.Int("hits", s.cacheHits))
	}()

	s.packageToDepsLock.RLock(pkg)
	s.lock.RLock()
	depResult, ok := s.packageToDeps[pkg]
	s.lock.RUnlock()
	s.packageToDepsLock.RUnlock(pkg)
	if ok {
		s.lock.Lock()
		s.calls++
		s.cacheHits++
		s.lock.Unlock()
		return depResult.Deps, depResult.Err
	}

	s.packageToDepsLock.Lock(pkg)
	defer s.packageToDepsLock.Unlock(pkg)

	s.lock.RLock()
	depResult, ok = s.packageToDeps[pkg]
	s.lock.RUnlock()
	if ok {
		s.lock.Lock()
		s.calls++
		s.cacheHits++
		s.lock.Unlock()
		return depResult.Deps, depResult.Err
	}
	deps, err := s.depsForPackageUncached(ctx, pkg)
	// we always hold key lock and then this lock so lock ordering is ok
	s.lock.Lock()
	s.packageToDeps[pkg] = newDepsResult(deps, err)
	s.calls++
	s.lock.Unlock()
	return deps, err
}

func (s *state) depsForPackageUncached(
	ctx context.Context,
	pkg string,
) (map[string]struct{}, error) {
	ctx, span := s.tracer.Start(ctx, "depsForPackageUncached", trace.WithAttributes(
		attribute.Key("package").String(pkg),
	))
	defer span.End()

	data, err := command.RunStdout(ctx, s.envStdioContainer, s.runner, `go`, `list`, `-f`, `{{join .Deps "\n"}}`, pkg)
	if err != nil {
		span.RecordError(err)
		span.SetStatus(codes.Error, err.Error())
		return nil, err
	}
	return stringutil.SliceToMap(getNonEmptyLines(string(data))), nil
}

type packagesResult struct {
	Packages map[string]struct{}
	Err      error
}

func newPackagesResult(
	packages map[string]struct{},
	err error,
) *packagesResult {
	return &packagesResult{
		Packages: packages,
		Err:      err,
	}
}

type depsResult struct {
	Deps map[string]struct{}
	Err  error
}

func newDepsResult(
	deps map[string]struct{},
	err error,
) *depsResult {
	return &depsResult{
		Deps: deps,
		Err:  err,
	}
}
