package main

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

type ExceptionData struct {
	Version    string      `json:"licenseListVersion"`
	Exceptions []Exception `json:"exceptions"`
}

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

// extractExceptionLicenseIDs read official exception licenses file copied from spdx/license-list-data
// and write file exception_license_ids.json containing just the non-deprecated exception license IDs.
// NOTE: For now, this function ignores the deprecated exception licenses.
func extractExceptionLicenseIDs() error {
	// open file
	file, err := os.Open("exceptions.json")
	if err != nil {
		fmt.Println(err)
		return err
	}

	// read in all licenses marshalled into a slice of exception structs
	var exceptionData ExceptionData
	err = json.NewDecoder(file).Decode(&exceptionData)
	if err != nil {
		return err
	}

	// create slice of exception license IDs that are not deprecated
	var exceptionLicenseIDs []string
	for _, e := range exceptionData.Exceptions {
		if !e.IsDeprecated {
			exceptionLicenseIDs = append(exceptionLicenseIDs, e.LicenseID)
		}
	}

	// generate the GetExceptions() function in get_exceptions.go
	getExceptionsContents := []byte(`package spdxlicenses

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

import "strings"

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

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

// GetExceptions returns a slice of exception license IDs.
func GetExceptions() []string {
	return []string{
`)
	for _, id := range exceptionLicenseIDs {
		getExceptionsContents = append(getExceptionsContents, `		"`+id+`",
`...)
	}
	getExceptionsContents = append(getExceptionsContents, `	}
}

`...)

	getExceptionsContents = append(getExceptionsContents, `var exceptionsMap = map[string]string{
`...)
	for _, id := range exceptionLicenseIDs {
		getExceptionsContents = append(getExceptionsContents, `		"`+strings.ToUpper(id)+`": "`+id+`",
`...)
	}
	getExceptionsContents = append(getExceptionsContents, `}
`...)

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

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

	return nil
}
