// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package analysis

import (
	"fmt"
	"io/ioutil"
	"log"

	"fidl-lsp/third_party/fidlgen"

	"fidl-lsp/state"
)

// ReferencesToSymbol returns the locations in `fs` of symbols that reference
// `sym`, as long as those locations are available to the Analyzer (i.e. in
// a.libs somewhere).
//
// For a library name, e.g. `fuchsia.foo`, ReferencesToSymbol returns the
// locations of the `using` import declarations for each file that imports that
// library.
func (a *Analyzer) ReferencesToSymbol(fs *state.FileSystem, sym state.Symbol) ([]state.Location, error) {
	// If `sym` is a library name, return locations pointing at all the files
	// that import that library (specifically, pointing at their `using`
	// declarations).
	libName, err := fidlgen.ReadLibraryName(sym.Name)
	if err == nil {
		// TODO: We could use getLibraryWithFile here, but it would be more
		// complicated: if this library name is a declaration, we should pass it
		// the file the symbol is in; but if it's a library import, we should
		// pass it a file of that imported library.
		if lib, isLib := a.getLibrary(libName); isLib {
			return a.importsOfLibrary(fs, lib.name), nil
		}
	}

	// Otherwise, we assume it is a local or fully-qualified name
	name, err := a.symbolToFullyQualifiedName(fs, sym)
	if err != nil {
		return nil, fmt.Errorf(
			"could not convert symbol `%s` to fully-qualified name: %s",
			sym.Name,
			err,
		)
	}

	// Search for references to `name` in all the libraries that import `name`'s
	// library, as well as its own library.
	libs := a.librariesThatImport(name.name.LibraryName())
	selfLibrary, ok := a.getLibrary(name.name.LibraryName())
	if !ok {
		return nil, fmt.Errorf("could not find library of symbol `%s`", sym.Name)
	}
	libs = append(libs, selfLibrary)
	refs := []state.Location{}

	for _, lib := range libs {
		if lib.ir == nil {
			if err := a.compileLibrary(lib); err != nil {
				log.Printf(
					"error importing library `%s`: %s",
					name.name.LibraryName().FullyQualifiedName(),
					err,
				)
				continue
			}
		}

		for _, si := range lib.symbols {
			if a.typeReferencesName(si.typeInfo, name.name) {
				refs = append(refs, si.definition)
			}
		}
	}

	return refs, nil
}

func (a *Analyzer) importsOfLibrary(fs *state.FileSystem, importedLib fidlgen.LibraryName) []state.Location {
	libs := a.librariesThatImport(importedLib)
	locs := []state.Location{}
	for _, lib := range libs {
		locs = append(locs, a.importsOfLibraryInLibrary(fs, importedLib, lib)...)
	}
	return locs
}

func (a *Analyzer) librariesThatImport(name fidlgen.LibraryName) []*Library {
	libs := []*Library{}
	for _, lib := range a.libs {
		for dep := range lib.deps {
			if dep == name {
				libs = append(libs, lib)
				break
			}
		}
	}
	return libs
}

func (a *Analyzer) importsOfLibraryInLibrary(fs *state.FileSystem, importedLib fidlgen.LibraryName, library *Library) []state.Location {
	files := []state.FileID{}
	for file := range library.files {
		// These files are all absolute paths, but some are to temporary input
		// files used by the Analyzer. For these, we want to convert the path
		// to the document URI the editor knows about.
		if fileID, err := a.inputFileToFileID(file); err == nil {
			files = append(files, fileID)
		} else {
			files = append(files, state.FileID(file))
		}
	}

	locs := []state.Location{}
	// Find the `using` declaration for `importedLib` in each file
	for _, fileID := range files {
		file, err := fs.File(fileID)
		if err != nil {
			// If we don't have the file in memory, read it in
			bytes, err := ioutil.ReadFile(string(fileID))
			if err != nil {
				log.Printf("could not read in file `%s`: %s", fileID, err)
				continue
			}
			file = string(bytes)
		}

		imports := state.ParsePlatformImportsMatch(file)
		for _, libraryMatch := range imports {
			if libraryMatch.Lib == importedLib {
				locs = append(locs, state.Location{
					FileID: fileID,
					Range:  libraryMatch.Range,
				})
			}
		}
	}
	return locs
}

func (a *Analyzer) typeReferencesName(t Type, name fidlgen.Name) bool {
	if t.FromTypeAlias != nil {
		if *t.FromTypeAlias == name.FullyQualifiedName() {
			return true
		}
		return false
	}

	switch t.Kind {
	default:
		return false

	case ArrayType:
		return a.typeReferencesName(t.Array.ElementType, name)

	case VectorType:
		return a.typeReferencesName(t.Vector.ElementType, name)

	case StringType:
		return false

	case HandleType:
		return false

	case RequestType:
		return t.Request.Subtype == name.FullyQualifiedName()

	case PrimitiveType:
		return false

	case IdentifierType:
		if !t.Identifier.IsDecl {
			return t.Identifier.Identifier == name.FullyQualifiedName()
		}
		if t.Identifier.Kind != TypeAliasKind {
			return false
		}
		return a.typeReferencesName(t.Identifier.TypeAlias.Type, name)
	}
}
