// Copyright 2019 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 repo

import (
	"encoding/json"
	"fmt"
	"strings"

	tuf_data "github.com/theupdateframework/go-tuf/data"
)

// Config is a struct that mirrors an associated FIDL table
// definition in //sdk/fidl/fuchsia.pkg/repo.fidl. Documentation is as in
// that file. Ditto for the types that comprise its definition.
//
// Keep these in sync with their repo.fidl counterparts as well as the custom
//
type Config struct {
	URL              string                `json:"repo_url"`
	RootKeys         []KeyConfig           `json:"root_keys"`
	Mirrors          []MirrorConfig        `json:"mirrors"`
	RootVersion      uint32                `json:"root_version"`
	RootThreshold    uint32                `json:"root_threshold"`
	UpdatePackageURL string                `json:"update_package_url,omitempty"`
	UseLocalMirror   bool                  `json:"use_local_mirror,omitempty"`
	StorageType      RepositoryStorageType `json:"storage_type,omitempty"`
}

type MirrorConfig struct {
	URL       string `json:"mirror_url"`
	Subscribe bool   `json:"subscribe"`
	BlobURL   string `json:"blob_mirror_url,omitempty"`
}

type KeyConfig struct {
	// ED25519Key is a 32-byte, lowercase, hex-encoded key.
	ED25519Key string
}

// The underlying type of the FIDL RepositoryStorageType is uint32,
// see //sdk/fidl/fuchsia.pkg/repo.fidl and
// https://fuchsia.dev/fuchsia-src/reference/fidl/language/language#enums
type RepositoryStorageType uint32

const (
	Unset RepositoryStorageType = iota
	Ephemeral
	Persistent
)

func (t RepositoryStorageType) MarshalJSON() ([]byte, error) {
	var s string
	switch t {
	case Unset:
		// s is empty and dropped during marshaling due to "omitempty"
	case Persistent:
		s = "persistent"
	case Ephemeral:
		s = "ephemeral"
	default:
		return []byte{}, fmt.Errorf("unknown repository storage type: %q", t)
	}
	return json.Marshal(s)
}

func (t *RepositoryStorageType) UnmarshalJSON(b []byte) error {
	var s string
	if err := json.Unmarshal(b, &s); err != nil {
		return err
	}
	switch strings.ToLower(s) {
	case "persistent":
		*t = Persistent
	case "ephemeral":
		*t = Ephemeral
	default:
		return fmt.Errorf("unknown repository storage type: %q", s)
	}
	return nil
}

// We replicate the serialization/deserialization logic given in
// //src/sys/pkg/lib/fidl-fuchsia-pkg-ext/src/repo.rs;
// Per this logic, we set the BlobURL field in MirrorConfig as omitempty (above),
// and give custom marshaling logic to the key config.
//

// This alias allows to make use of the default (un)marshalling logic of Config as we redefine it.
type config Config

func (cfg *Config) MarshalJSON() ([]byte, error) {
	cfg2 := config(*cfg)
	if cfg2.RootVersion == 0 {
		cfg2.RootVersion = 1
	}
	if cfg2.RootThreshold == 0 {
		cfg2.RootThreshold = 1
	}
	return json.Marshal(&cfg2)
}

func (cfg *Config) UnmarshalJSON(data []byte) error {
	var cfg2 config
	if err := json.Unmarshal(data, &cfg2); err != nil {
		return err
	}
	if cfg2.RootVersion == 0 {
		cfg2.RootVersion = 1
	}
	if cfg2.RootThreshold == 0 {
		cfg2.RootThreshold = 1
	}
	*cfg = Config(cfg2)
	return nil
}

type typeAndValue struct {
	Type  string `json:"type"`
	Value string `json:"value"`
}

func (key *KeyConfig) MarshalJSON() ([]byte, error) {
	return json.Marshal(&typeAndValue{
		Type:  tuf_data.KeyTypeEd25519,
		Value: key.ED25519Key,
	})
}

func (key *KeyConfig) UnmarshalJSON(data []byte) error {
	var tv typeAndValue
	if err := json.Unmarshal(data, &tv); err != nil {
		return err
	}

	switch tv.Type {
	case tuf_data.KeyTypeEd25519:
		key.ED25519Key = tv.Value
		return nil
	default:
		return fmt.Errorf("unexpected key type: %q", tv.Type)
	}
}

// GetRootKeys returns the list of public key config objects as read from the
// contents of a repository's root metadata file.
func GetRootKeys(root *tuf_data.Root) ([]KeyConfig, error) {
	rootKeys := make(map[string]struct{})
	if role, ok := root.Roles["root"]; ok {
		for _, id := range role.KeyIDs {
			if key, ok := root.Keys[id]; ok {
				switch key.Type {
				case tuf_data.KeyTypeEd25519:
					var kv struct {
						Public tuf_data.HexBytes `json:"public"`
					}
					if err := json.Unmarshal(key.Value, &kv); err != nil {
						return nil, fmt.Errorf("failed to unmarshal key: %w", err)
					}
					rootKeys[kv.Public.String()] = struct{}{}
				default:
					return nil, fmt.Errorf("unexpected key type: %q", key.Type)
				}
			}
		}
	}
	rootKeyConfigs := make([]KeyConfig, 0, len(rootKeys))
	for key := range rootKeys {
		rootKeyConfigs = append(rootKeyConfigs, KeyConfig{ED25519Key: key})
	}
	return rootKeyConfigs, nil
}
