package main

import (
	"bytes"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"text/template"

	"gopkg.in/yaml.v2"
)

// Subproject struct to hold subproject data.
type Subproject struct {
	Name    string  `yaml:"name"`
	Contact Contact `yaml:"contact"`
}

// Term struct to hold start and end dates.
type Term struct {
	Start string `yaml:"start,omitempty"`
	End   string `yaml:"end,omitempty"`
}

// Person struct to hold person data, including company and term.
type Person struct {
	Name    string `yaml:"name"`
	GitHub  string `yaml:"github"`
	Company string `yaml:"company,omitempty"`
	Term    Term   `yaml:"term,omitempty"` // ADDED: Term for leadership roles
}

// Leadership struct to hold all leadership roles.
type Leadership struct {
	Chairs          []Person `yaml:"chairs"`
	TechLeads       []Person `yaml:"tech_leads"`
	SubprojectLeads []Person `yaml:"Subpproject Leads"`
}

// Meeting struct to hold meeting data.
type Meeting struct {
	Description   string `yaml:"description"`
	RecordingsURL string `yaml:"recordings_url"`
	TagCalendar   string `yaml:"tag_calendar,omitempty"`
}

// Contact struct to hold contact information.
type Contact struct {
	Slack       string   `yaml:"slack"`
	MailingList string   `yaml:"mailing_list"`
	TOCLiaison  []Person `yaml:"toc_liaison"`
}

// Tag struct to hold tag data, including CharterLink and Subprojects.
type Tag struct {
	Dir              string       `yaml:"dir"`
	Name             string       `yaml:"name"`
	MissionStatement string       `yaml:"mission_statement"`
	Leadership       Leadership   `yaml:"leadership"`
	Meetings         []Meeting    `yaml:"meetings"`
	Contact          Contact      `yaml:"contact"`
	TagSubprojects   []Subproject `yaml:"tag_subprojects"`
	// The following are all generated, and the fields in the YAML file are ignored.
	CharterLink    string `yaml:"charter_link"`
	TagLabel       string `yaml:"tag_label"`
	TagInitiatives string `yaml:"tag_initiatives"`
}

// TOCSubproject struct to hold TOC subproject data, including CharterLink.
type TOCSubproject struct {
	Dir              string     `yaml:"dir"`
	Name             string     `yaml:"name"`
	MissionStatement string     `yaml:"mission_statement"`
	Leadership       Leadership `yaml:"leadership"`
	Meetings         []Meeting  `yaml:"meetings"`
	Contact          Contact    `yaml:"contact"`
	// The following are all generated, and the fields in the YAML file are ignored.
	CharterLink           string `yaml:"charter_link"`
	SubprojectInitiatives string `yaml:"subproject_initiatives"`
	SubprojectLabel       string `yaml:"subproject_label"`
}

// Config struct to hold the entire configuration.
type Config struct {
	Tags           []Tag           `yaml:"tags"`
	TOCSubprojects []TOCSubproject `yaml:"toc_subprojects"`
}

func main() {
	// Define paths.
	configPath := filepath.Join("..", "tags.yaml")
	tagsDir := filepath.Join("..", "tags")
	tocDir := filepath.Join("..", "toc_subprojects")
	tagTemplatePath := filepath.Join("..", "generator", "tag_readme.tmpl")
	tocTemplatePath := filepath.Join("..", "generator", "toc_subproject_readme.tmpl")

	// Read YAML file.
	data, err := os.ReadFile(configPath)
	if err != nil {
		log.Fatalf("Failed to read tags.yaml: %v", err)
	}

	var config Config
	if err := yaml.Unmarshal(data, &config); err != nil {
		log.Fatalf("Failed to parse YAML: %v", err)
	}

	// Load templates.
	tagTmplContent, err := os.ReadFile(tagTemplatePath)
	if err != nil {
		log.Fatalf("Failed to read tag template: %v", err)
	}
	tagTmpl, err := template.New("tag_readme").Parse(string(tagTmplContent))
	if err != nil {
		log.Fatalf("Failed to parse tag template: %v", err)
	}

	tocTmplContent, err := os.ReadFile(tocTemplatePath)
	if err != nil {
		log.Fatalf("Failed to read toc template: %v", err)
	}
	tocTmpl, err := template.New("toc_readme").Parse(string(tocTmplContent))
	if err != nil {
		log.Fatalf("Failed to parse toc template: %v", err)
	}

	// Ensure directories exist.
	if err := ensureDir(tagsDir); err != nil {
		log.Fatalf("Failed to create tags directory: %v", err)
	}
	if err := ensureDir(tocDir); err != nil {
		log.Fatalf("Failed to create TOC Subprojects directory: %v", err)
	}

	// Process each tag.
	for _, tag := range config.Tags {
		tagFolderPath := filepath.Join(tagsDir, tag.Dir)
		if err := ensureDir(tagFolderPath); err != nil {
			log.Fatalf("Failed to create folder for tag %s: %v", tag.Name, err)
		}

		charterPath := filepath.Join(tagFolderPath, "charter.md")
		if _, err := os.Stat(charterPath); os.IsNotExist(err) {
			if err := os.WriteFile(charterPath, []byte("Charter content here"), 0o644); err != nil {
				log.Fatalf("Failed to write %s: %v", charterPath, err)
			}
		}
		// Autofill template fields that should be invariant.
		tag.CharterLink = charterPath
		// TagLabel is the part of the label after the "tag/" prefix.
		tag.TagLabel = strings.ReplaceAll(
			strings.TrimSpace(
				strings.TrimPrefix(strings.ToLower(tag.Name), "tag")), " ", "-")

		var tagBuf bytes.Buffer
		if err := tagTmpl.Execute(&tagBuf, tag); err != nil {
			log.Fatalf("Tag template execution failed: %v", err)
		}

		tagFilePath := filepath.Join(tagFolderPath, "README.md")
		if err := os.WriteFile(tagFilePath, tagBuf.Bytes(), 0o644); err != nil {
			log.Fatalf("Failed to write %s: %v", tagFilePath, err)
		}
	}

	// Process each TOC subproject.
	for _, tocSubproject := range config.TOCSubprojects {
		tocSubprojectFolderPath := filepath.Join(tocDir, tocSubproject.Dir)
		if err := ensureDir(tocSubprojectFolderPath); err != nil {
			log.Fatalf("Failed to create folder for TOC subproject %s: %v", tocSubproject.Name, err)
		}

		charterPath := filepath.Join(tocSubprojectFolderPath, "charter.md")
		if _, err := os.Stat(charterPath); os.IsNotExist(err) {
			if err := os.WriteFile(charterPath, []byte("Charter content here"), 0o644); err != nil {
				log.Fatalf("Failed to write %s: %v", charterPath, err)
			}
		}
		// Autofill template fields that should be invariant.
		tocSubproject.CharterLink = charterPath
		// SubprojectLabel is the part of the label after the "sub/" prefix.
		tocSubproject.SubprojectLabel = strings.ReplaceAll(
			strings.TrimSpace(
				strings.TrimSuffix(strings.ToLower(tocSubproject.Name), "subproject")), " ", "-")

		var tocBuf bytes.Buffer
		if err := tocTmpl.Execute(&tocBuf, tocSubproject); err != nil {
			log.Fatalf("TOC template execution failed: %v", err)
		}

		tocReadmePath := filepath.Join(tocSubprojectFolderPath, "README.md")
		if err := os.WriteFile(tocReadmePath, tocBuf.Bytes(), 0o644); err != nil {
			log.Fatalf("Failed to write %s: %v", tocReadmePath, err)
		}
	}

	log.Println("Tag, Subproject, and README files have been generated.")
}

// ensureDir ensures the directory exists.
func ensureDir(dirPath string) error {
	if err := os.MkdirAll(dirPath, 0o755); err != nil {
		return fmt.Errorf("failed to create directory %s: %w", dirPath, err)
	}
	return nil
}
