package main

import (
	"encoding/json"
	"fmt"
	"go/format"
	"os"
	"strings"
)

type LicenseData struct {
	Version  string    `json:"licenseListVersion"`
	Licenses []License `json:"licenses"`
}

type License struct {
	Reference       string   `json:"reference"`
	IsDeprecated    bool     `json:"isDeprecatedLicenseId"`
	DetailsURL      string   `json:"detailsUrl"`
	ReferenceNumber int      `json:"referenceNumber"`
	Name            string   `json:"name"`
	LicenseID       string   `json:"licenseId"`
	SeeAlso         []string `json:"seeAlso"`
	IsOsiApproved   bool     `json:"isOsiApproved"`
}

// extractLicenseIDs reads the official licenses.json file copied from spdx/license-list-data
// and writes two files, license_ids.json and deprecated_license_ids.json, containing just
// the license IDs and deprecated license IDs, respectively.  It returns an error if it
// encounters one.
func extractLicenseIDs() error {
	// open file
	file, err := os.Open("licenses.json")
	if err != nil {
		fmt.Println(err)
		return err
	}

	// read in all licenses marshalled into a slice of license structs
	var licenseData LicenseData
	err = json.NewDecoder(file).Decode(&licenseData)
	if err != nil {
		fmt.Println(err)
		return err
	}

	// create two slices of license IDs, one for deprecated and one for active
	var activeLicenseIDs []string
	var deprecatedLicenseIDs []string
	for _, l := range licenseData.Licenses {
		if l.IsDeprecated {
			deprecatedLicenseIDs = append(deprecatedLicenseIDs, l.LicenseID)
		} else {
			activeLicenseIDs = append(activeLicenseIDs, l.LicenseID)
		}
	}

	// generate the GetLicenses() function in get_licenses.go
	getLicensesContents := []byte(`package spdxlicenses

// Code generated by go-spdx cmd/license.go. DO NOT EDIT.
// Source: https://github.com/spdx/license-list-data specifies official SPDX license list.

import "strings"

// IsActiveLicense does a case-insensitive lookup for the license id in the active licenses map.
// It returns true and the case-sensitive ID if found, otherwise false and the original id.
func IsActiveLicense(id string) (bool, string) {
	foundID, ok := licensesMap[strings.ToUpper(id)]
	if ok {
		return true, foundID
	}
	return false, id
}

// GetLicensesMap returns a map of active license IDs keyed by uppercase ID.
func GetLicensesMap() map[string]string {
   	copied := make(map[string]string, len(licensesMap))  
    for k, v := range licensesMap {  
        copied[k] = v  
    }  
    return copied
}

// GetLicenses returns a slice of active license IDs.
func GetLicenses() []string {
	return []string{
`)
	for _, id := range activeLicenseIDs {
		getLicensesContents = append(getLicensesContents, `		"`+id+`",
`...)
	}
	getLicensesContents = append(getLicensesContents, `	}
}

`...)

	getLicensesContents = append(getLicensesContents, `var licensesMap = map[string]string{
`...)
	for _, id := range activeLicenseIDs {
		getLicensesContents = append(getLicensesContents, `		"`+strings.ToUpper(id)+`": "`+id+`",
`...)
	}
	getLicensesContents = append(getLicensesContents, `}
`...)

	getLicensesContents, err = format.Source(getLicensesContents)
	if err != nil {
		return fmt.Errorf("format generated get_licenses.go: %w", err)
	}

	err = os.WriteFile("../spdxexp/spdxlicenses/get_licenses.go", getLicensesContents, 0600)
	if err != nil {
		return err
	}
	fmt.Println("Writing `../spdxexp/spdxlicenses/get_licenses.go`... COMPLETE")

	// generate the GetDeprecated() function in get_deprecated.go
	getDeprecatedContents := []byte(`package spdxlicenses

// Code generated by go-spdx cmd/license.go. DO NOT EDIT.
// Source: https://github.com/spdx/license-list-data specifies official SPDX license list.

import "strings"

// IsDeprecatedLicense does a case-insensitive lookup for the license id in the deprecated licenses map.
// It returns true and the case-sensitive ID if found, otherwise false and the original id.
func IsDeprecatedLicense(id string) (bool, string) {
	foundID, ok := deprecatedMap[strings.ToUpper(id)]
	if ok {
		return true, foundID
	}
	return false, id
}

// GetDeprecatedMap returns a map of deprecated license IDs keyed by uppercase ID.
func GetDeprecatedMap() map[string]string {
   	copied := make(map[string]string, len(deprecatedMap))  
    for k, v := range deprecatedMap {  
        copied[k] = v  
    }  
    return copied
}

// GetDeprecated returns a slice of deprecated license IDs.
func GetDeprecated() []string {
	return []string{
`)
	for _, id := range deprecatedLicenseIDs {
		getDeprecatedContents = append(getDeprecatedContents, `		"`+id+`",
`...)
	}
	getDeprecatedContents = append(getDeprecatedContents, `	}
}

`...)

	getDeprecatedContents = append(getDeprecatedContents, `var deprecatedMap = map[string]string{
`...)
	for _, id := range deprecatedLicenseIDs {
		getDeprecatedContents = append(getDeprecatedContents, `		"`+strings.ToUpper(id)+`": "`+id+`",
`...)
	}
	getDeprecatedContents = append(getDeprecatedContents, `}
`...)

	getDeprecatedContents, err = format.Source(getDeprecatedContents)
	if err != nil {
		return fmt.Errorf("format generated get_deprecated.go: %w", err)
	}

	err = os.WriteFile("../spdxexp/spdxlicenses/get_deprecated.go", getDeprecatedContents, 0600)
	if err != nil {
		return err
	}
	fmt.Println("Writing `../spdxexp/spdxlicenses/get_deprecated.go`... COMPLETE")

	return nil
}
