package models

import (
	"reflect"
	"regexp"
	"strings"
	"time"
)

const (
	HMNProjectID   = 1
	HMNProjectSlug = "hmn"
)

var ProjectType = reflect.TypeOf(Project{})

type ProjectLifecycle int

const (
	ProjectLifecycleUnapproved ProjectLifecycle = iota
	ProjectLifecycleApprovalRequired
	ProjectLifecycleActive
	ProjectLifecycleHiatus
	ProjectLifecycleDead
	ProjectLifecycleLTSRequired
	ProjectLifecycleLTS
)

var AllProjectLifecycles = []ProjectLifecycle{
	ProjectLifecycleUnapproved,
	ProjectLifecycleApprovalRequired,
	ProjectLifecycleActive,
	ProjectLifecycleHiatus,
	ProjectLifecycleDead,
	ProjectLifecycleLTSRequired,
	ProjectLifecycleLTS,
}

// NOTE(asaf): Just checking the lifecycle is not sufficient. Visible projects also must not be hidden.
var VisibleProjectLifecycles = []ProjectLifecycle{
	ProjectLifecycleActive,
	ProjectLifecycleHiatus,
	ProjectLifecycleLTSRequired, // NOTE(asaf): LTS means complete
	ProjectLifecycleLTS,
}

func (lc ProjectLifecycle) In(lcs []ProjectLifecycle) bool {
	for _, v := range lcs {
		if lc == v {
			return true
		}
	}
	return false
}

const RecentProjectUpdateTimespanSec = 60 * 60 * 24 * 28 // NOTE(asaf): Four weeks

type Project struct {
	ID int `db:"id"`

	ForumID *int `db:"forum_id"`

	Slug              string `db:"slug"`
	Name              string `db:"name"`
	TagID             *int   `db:"tag"`
	Blurb             string `db:"blurb"`
	Description       string `db:"description"`
	ParsedDescription string `db:"descparsed"`

	Lifecycle ProjectLifecycle `db:"lifecycle"` // TODO(asaf): Ensure we only fetch projects in the correct lifecycle phase everywhere.

	Color1 string `db:"color_1"`
	Color2 string `db:"color_2"`

	Personal              bool      `db:"personal"`
	Hidden                bool      `db:"hidden"`
	Featured              bool      `db:"featured"`
	DateApproved          time.Time `db:"date_approved"`
	DateCreated           time.Time `db:"date_created"`
	AllLastUpdated        time.Time `db:"all_last_updated"`
	ForumLastUpdated      time.Time `db:"forum_last_updated"`
	BlogLastUpdated       time.Time `db:"blog_last_updated"`
	AnnotationLastUpdated time.Time `db:"annotation_last_updated"`

	ForumEnabled   bool `db:"forum_enabled"`
	BlogEnabled    bool `db:"blog_enabled"`
	LibraryEnabled bool `db:"library_enabled"` // TODO: Delete this field from the db
}

func (p *Project) IsHMN() bool {
	return p.ID == HMNProjectID
}

func (p *Project) Subdomain() string {
	if p.IsHMN() {
		return ""
	}

	return p.Slug
}

// Checks whether the project has forums enabled. This should restrict the creation of new forum
// content, but it should NOT prevent the viewing of existing forum content. (Projects may at one
// point have forums enabled, write some stuff, and then later disable forums, and we want that
// content to stay accessible.) Hiding the navigation is ok.
func (p *Project) HasForums() bool {
	return !p.Personal && p.ForumEnabled
}

// Same as HasForums, but for blogs.
func (p *Project) HasBlog() bool {
	return !p.Personal && p.BlogEnabled
}

var slugUnsafeChars = regexp.MustCompile(`[^a-zA-Z0-9-]`)
var slugHyphenRun = regexp.MustCompile(`-+`)

// Generates a URL-safe version of a personal project's name.
func GeneratePersonalProjectSlug(name string) string {
	slug := name
	slug = slugUnsafeChars.ReplaceAllLiteralString(slug, "-")
	slug = slugHyphenRun.ReplaceAllLiteralString(slug, "-")
	slug = strings.Trim(slug, "-")
	slug = strings.ToLower(slug)

	return slug
}
