package model

import (
	"encoding/json"
	"fmt"

	v3 "github.com/anchore/grype/grype/db/v3"
)

const (
	VulnerabilityMetadataTableName = "vulnerability_metadata"
)

// VulnerabilityMetadataModel is a struct used to serialize db.VulnerabilityMetadata information into a sqlite3 DB.
type VulnerabilityMetadataModel struct {
	ID           string `gorm:"primary_key; column:id;"`
	Namespace    string `gorm:"primary_key; column:namespace;"`
	DataSource   string `gorm:"column:data_source"`
	RecordSource string `gorm:"column:record_source"`
	Severity     string `gorm:"column:severity"`
	URLs         string `gorm:"column:urls"`
	Description  string `gorm:"column:description"`
	Cvss         string `gorm:"column:cvss"`
}

// NewVulnerabilityMetadataModel generates a new model from a db.VulnerabilityMetadata struct.
func NewVulnerabilityMetadataModel(metadata v3.VulnerabilityMetadata) VulnerabilityMetadataModel {
	links, err := json.Marshal(metadata.URLs)
	if err != nil {
		// TODO: just no
		panic(err)
	}

	if metadata.Cvss == nil {
		metadata.Cvss = make([]v3.Cvss, 0)
	}
	var cvssStr string
	cvss, err := json.Marshal(metadata.Cvss)
	if err != nil {
		// TODO: just no
		panic(err)
	}

	cvssStr = string(cvss)

	return VulnerabilityMetadataModel{
		ID:           metadata.ID,
		Namespace:    metadata.Namespace,
		DataSource:   metadata.DataSource,
		RecordSource: metadata.RecordSource,
		Severity:     metadata.Severity,
		URLs:         string(links),
		Description:  metadata.Description,
		Cvss:         cvssStr,
	}
}

// TableName returns the table which all db.VulnerabilityMetadata model instances are stored into.
func (VulnerabilityMetadataModel) TableName() string {
	return VulnerabilityMetadataTableName
}

// Inflate generates a db.VulnerabilityMetadataModel object from the serialized model instance.
func (m *VulnerabilityMetadataModel) Inflate() (v3.VulnerabilityMetadata, error) {
	var links []string
	var cvss []v3.Cvss

	if err := json.Unmarshal([]byte(m.URLs), &links); err != nil {
		return v3.VulnerabilityMetadata{}, fmt.Errorf("unable to unmarshal URLs (%+v): %w", m.URLs, err)
	}

	err := json.Unmarshal([]byte(m.Cvss), &cvss)
	if err != nil {
		return v3.VulnerabilityMetadata{}, fmt.Errorf("unable to unmarshal cvss data (%+v): %w", m.Cvss, err)
	}

	return v3.VulnerabilityMetadata{
		ID:           m.ID,
		Namespace:    m.Namespace,
		DataSource:   m.DataSource,
		RecordSource: m.RecordSource,
		Severity:     m.Severity,
		URLs:         links,
		Description:  m.Description,
		Cvss:         cvss,
	}, nil
}
