package extension_repo

import (
	"errors"
	"fmt"
	"regexp"
	"seanime/internal/extension"
	"seanime/internal/util"
	"strings"
)

func pluginManifestSanityCheck(ext *extension.Extension) error {
	// Not a plugin, so no need to check
	if ext.Type != extension.TypePlugin {
		return nil
	}

	// Check plugin manifest
	if ext.Plugin == nil {
		return fmt.Errorf("plugin manifest is missing")
	}

	// Check plugin manifest version
	if ext.Plugin.Version == "" {
		return fmt.Errorf("plugin manifest version is missing")
	}

	// Check plugin permissions version
	if ext.Plugin.Version != extension.PluginManifestVersion {
		return fmt.Errorf("unsupported plugin manifest version: %v", ext.Plugin.Version)
	}

	return nil
}

func manifestSanityCheck(ext *extension.Extension) error {
	if ext.ID == "" || ext.Name == "" || ext.Version == "" || ext.Language == "" || ext.Type == "" || ext.Author == "" {
		return fmt.Errorf("extension is missing required fields, ID: %v, Name: %v, Version: %v, Language: %v, Type: %v, Author: %v, Payload: %v",
			ext.ID, ext.Name, ext.Version, ext.Language, ext.Type, ext.Author, len(ext.Payload))
	}

	if ext.Payload == "" && ext.PayloadURI == "" {
		return fmt.Errorf("extension is missing payload and payload URI")
	}

	// Check the ID
	if err := isValidExtensionID(ext.ID); err != nil {
		return err
	}

	// Check name length
	if len(ext.Name) > 50 {
		return fmt.Errorf("extension name is too long")
	}

	// Check author length
	if len(ext.Author) > 25 {
		return fmt.Errorf("extension author is too long")
	}

	if !util.IsValidVersion(ext.Version) {
		return fmt.Errorf("invalid version: %v", ext.Version)
	}

	// Check language
	if ext.Language != extension.LanguageGo &&
		ext.Language != extension.LanguageJavascript &&
		ext.Language != extension.LanguageTypescript {
		return fmt.Errorf("unsupported language: %v", ext.Language)
	}

	// Check type
	if ext.Type != extension.TypeMangaProvider &&
		ext.Type != extension.TypeOnlinestreamProvider &&
		ext.Type != extension.TypeAnimeTorrentProvider &&
		ext.Type != extension.TypePlugin {
		return fmt.Errorf("unsupported extension type: %v", ext.Type)
	}

	if ext.Type == extension.TypePlugin {
		if err := pluginManifestSanityCheck(ext); err != nil {
			return err
		}
	}

	ext.Lang = strings.ToLower(ext.Lang)

	return nil
}

// extensionSanityCheck checks if the extension has all the required fields in the manifest.
func (r *Repository) extensionSanityCheck(ext *extension.Extension) error {

	if err := manifestSanityCheck(ext); err != nil {
		return err
	}

	// Check that the ID is unique
	if err := r.isUniqueExtensionID(ext.ID); err != nil {
		return err
	}

	return nil
}

// checks if the extension ID is valid
// Note: The ID must start with a letter and contain only alphanumeric characters
// because it can either be used as a package name or appear in a filename
func isValidExtensionID(id string) error {
	if id == "" {
		return errors.New("extension ID is empty")
	}
	if len(id) > 40 {
		return errors.New("extension ID is too long")
	}
	if len(id) < 3 {
		return errors.New("extension ID is too short")
	}

	if !isValidExtensionIDString(id) {
		return errors.New("extension ID contains invalid characters")
	}

	return nil
}

func isValidExtensionIDString(id string) bool {
	// Check if the ID starts with a letter and contains only alphanumeric characters
	re := regexp.MustCompile(`^[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9]$`)
	ok := re.MatchString(id)

	if !ok {
		return false
	}
	return true
}

func (r *Repository) isUniqueExtensionID(id string) error {
	// Check if the ID is not a reserved built-in extension ID
	_, found := r.extensionBank.Get(id)
	if found {
		return errors.New("extension ID is already in use")
	}
	return nil
}

func ReplacePackageName(src string, newPkgName string) string {
	rgxp, err := regexp.Compile(`package \w+`)
	if err != nil {
		return ""
	}

	ogPkg := rgxp.FindString(src)
	if ogPkg == "" {
		return src
	}

	return strings.Replace(src, ogPkg, "package "+newPkgName, 1)
}
