package main

import (
	"bytes"
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"

	"git.godopu.com/lab/landing_page/backend/internal/config"
	"git.godopu.com/lab/landing_page/backend/internal/db"
	"git.godopu.com/lab/landing_page/backend/internal/repository"
)

func marshalJSONNoEscapeHTML(data any) ([]byte, error) {
	var buf bytes.Buffer
	enc := json.NewEncoder(&buf)
	enc.SetEscapeHTML(false)
	enc.SetIndent("", "  ")
	if err := enc.Encode(data); err != nil {
		return nil, err
	}
	return bytes.TrimRight(buf.Bytes(), "\n"), nil
}

func formatTSFile(importStmt, exportConstName, typeAnnotation string, data any) ([]byte, error) {
	jsonData, err := marshalJSONNoEscapeHTML(data)
	if err != nil {
		return nil, fmt.Errorf("marshal JSON: %w", err)
	}

	header := "// AUTO-GENERATED by backend/cmd/export-content — DO NOT EDIT BY HAND\n"
	content := fmt.Sprintf("%s%s\n\nexport const %s: %s = %s;\n", header, importStmt, exportConstName, typeAnnotation, string(jsonData))
	return []byte(content), nil
}

func writeFileSafe(path string, data []byte) error {
	return os.WriteFile(path, data, 0644)
}

func main() {
	config.LoadEnvFile()
	defaultDB := "anl.db"
	if envDB := os.Getenv("DB_PATH"); envDB != "" {
		defaultDB = envDB
	}

	dbPath := flag.String("db", defaultDB, "Path to SQLite database file")
	targetDir := flag.String("out-dir", "../refer_landing_page/content", "Target content directory")
	force := flag.Bool("force", false, "Force export content files despite dynamic runtime architecture")
	flag.Parse()

	if !*force {
		log.Printf("⚠️ NOTICE: Frontend architecture has migrated to real-time dynamic runtime fetching (force-dynamic).")
		log.Printf("Exporting static TypeScript files to %s is DEPRECATED to prevent re-introducing static fallback leaks.", *targetDir)
		log.Printf("If you really need to export fallback files, pass the --force flag.")
		return
	}

	log.Printf("Exporting content from SQLite (%s) to TypeScript files in %s (forced)...", *dbPath, *targetDir)
	database, err := db.Connect(*dbPath)
	if err != nil {
		log.Fatalf("Failed to connect to database: %v", err)
	}
	defer database.Close()

	ctx := context.Background()
	homeRepo := repository.NewHomeRepository(database)
	membersRepo := repository.NewMembersRepository(database)
	pubsRepo := repository.NewPublicationsRepository(database)
	lecturesRepo := repository.NewLecturesRepository(database)
	standardsRepo := repository.NewStandardizationRepository(database)

	// 1. Projects
	projects, err := homeRepo.GetResearchProjects(ctx)
	if err != nil {
		log.Fatalf("Get research projects: %v", err)
	}
	type TSProject struct {
		Slug           string   `json:"slug"`
		Title          string   `json:"title"`
		Abstract       string   `json:"abstract"`
		Keywords       []string `json:"keywords"`
		StandardsTrack *string  `json:"standardsTrack,omitempty"`
		StandardsOrg   *string  `json:"standardsOrg,omitempty"`
		Period         *string  `json:"period,omitempty"`
		Deliverables   []any    `json:"deliverables"`
		Funder         *string  `json:"funder,omitempty"`
	}
	var tsProjects []TSProject
	for _, p := range projects {
		tsProjects = append(tsProjects, TSProject{
			Slug:           p.Slug,
			Title:          p.Title,
			Abstract:       p.Abstract,
			Keywords:       p.Keywords,
			StandardsTrack: p.Organization,
			StandardsOrg:   p.StandardsOrg,
			Period:         p.Period,
			Deliverables:   []any{},
			Funder:         p.Funder,
		})
	}
	pBytes, err := formatTSFile(`import { ResearchProject } from "./types";`, "researchProjects", "ResearchProject[]", tsProjects)
	if err != nil {
		log.Fatalf("Format projects.ts failed: %v", err)
	}
	if err := writeFileSafe(filepath.Join(*targetDir, "projects.ts"), pBytes); err != nil {
		log.Fatalf("Write projects.ts failed: %v", err)
	}
	log.Println("✓ Exported projects.ts")

	// 2. Members & Alumni
	members, err := membersRepo.GetMembers(ctx)
	if err != nil {
		log.Fatalf("Get members: %v", err)
	}
	type TSMember struct {
		Ko          string  `json:"ko"`
		En          string  `json:"en"`
		Degree      string  `json:"degree"`
		Affiliation *string `json:"affiliation,omitempty"`
	}
	var tsMembers []TSMember
	for _, m := range members {
		tsMembers = append(tsMembers, TSMember{
			Ko:          m.NameKo,
			En:          m.NameEn,
			Degree:      m.Degree,
			Affiliation: m.Affiliation,
		})
	}

	alumni, err := membersRepo.GetAlumni(ctx)
	if err != nil {
		log.Fatalf("Get alumni: %v", err)
	}
	type TSAlumnus struct {
		Ko              string  `json:"ko"`
		En              string  `json:"en"`
		Degree          string  `json:"degree"`
		GraduatedAt     string  `json:"graduatedAt"`
		Major           *string `json:"major,omitempty"`
		CurrentPosition *string `json:"currentPosition,omitempty"`
	}
	var tsAlumni []TSAlumnus
	for _, a := range alumni {
		tsAlumni = append(tsAlumni, TSAlumnus{
			Ko:              a.NameKo,
			En:              a.NameEn,
			Degree:          a.Degree,
			GraduatedAt:     a.GraduatedAt,
			Major:           a.Major,
			CurrentPosition: a.CurrentPosition,
		})
	}

	mJSON, err := marshalJSONNoEscapeHTML(tsMembers)
	if err != nil {
		log.Fatalf("Marshal members failed: %v", err)
	}
	aJSON, err := marshalJSONNoEscapeHTML(tsAlumni)
	if err != nil {
		log.Fatalf("Marshal alumni failed: %v", err)
	}
	membersTS := fmt.Sprintf("// AUTO-GENERATED by backend/cmd/export-content — DO NOT EDIT BY HAND\nimport { Member, Alumnus } from \"./types\";\n\nexport const activeMembers: Member[] = %s;\n\nexport const alumni: Alumnus[] = %s;\n", string(mJSON), string(aJSON))
	if err := writeFileSafe(filepath.Join(*targetDir, "members.ts"), []byte(membersTS)); err != nil {
		log.Fatalf("Write members.ts failed: %v", err)
	}
	log.Println("✓ Exported members.ts")

	// 3. Publications & Patents
	pubs, err := pubsRepo.GetPublications(ctx, "")
	if err != nil {
		log.Fatalf("Get publications: %v", err)
	}
	type TSPublication struct {
		Category    string  `json:"category"`
		Title       string  `json:"title"`
		Authors     *string `json:"authors,omitempty"`
		Venue       string  `json:"venue"`
		Volume      *string `json:"volume,omitempty"`
		PublishedAt string  `json:"publishedAt"`
		KCI         bool    `json:"kci,omitempty"`
		DOI         *string `json:"doi,omitempty"`
		IsHighlight bool    `json:"isHighlight,omitempty"`
	}
	var tsPubs []TSPublication
	for _, p := range pubs {
		tsPubs = append(tsPubs, TSPublication{
			Category:    p.Category,
			Title:       p.Title,
			Authors:     p.Authors,
			Venue:       p.Venue,
			Volume:      p.Volume,
			PublishedAt: p.PublishedAt,
			KCI:         p.KCI,
			DOI:         p.DOI,
			IsHighlight: p.IsHighlight,
		})
	}

	patents, err := pubsRepo.GetPatents(ctx)
	if err != nil {
		log.Fatalf("Get patents: %v", err)
	}
	type TSPatent struct {
		Category       string  `json:"category"`
		Title          string  `json:"title"`
		Inventors      string  `json:"inventors"`
		ApplicationNo  string  `json:"applicationNo"`
		ApplicationAt  string  `json:"applicationAt"`
		RegistrationNo *string `json:"registrationNo,omitempty"`
		RegistrationAt *string `json:"registrationAt,omitempty"`
		Country        string  `json:"country"`
		PublishedAt    string  `json:"publishedAt"`
	}
	var tsPatents []TSPatent
	for _, pat := range patents {
		tsPatents = append(tsPatents, TSPatent{
			Category:       "patent",
			Title:          pat.Title,
			Inventors:      pat.Inventors,
			ApplicationNo:  pat.ApplicationNo,
			ApplicationAt:  pat.ApplicationAt,
			RegistrationNo: pat.RegistrationNo,
			RegistrationAt: pat.RegistrationAt,
			Country:        pat.Country,
			PublishedAt:    pat.PublishedAt,
		})
	}

	pubsJSON, err := marshalJSONNoEscapeHTML(tsPubs)
	if err != nil {
		log.Fatalf("Marshal publications failed: %v", err)
	}
	patentsJSON, err := marshalJSONNoEscapeHTML(tsPatents)
	if err != nil {
		log.Fatalf("Marshal patents failed: %v", err)
	}
	pubsTS := fmt.Sprintf("// AUTO-GENERATED by backend/cmd/export-content — DO NOT EDIT BY HAND\nimport { Publication, Patent } from \"./types\";\n\nexport const publications: Publication[] = %s;\n\nexport const patents: Patent[] = %s;\n", string(pubsJSON), string(patentsJSON))
	if err := writeFileSafe(filepath.Join(*targetDir, "publications.ts"), []byte(pubsTS)); err != nil {
		log.Fatalf("Write publications.ts failed: %v", err)
	}
	log.Println("✓ Exported publications.ts (with isHighlight metadata & unescaped HTML entities)")

	// 4. Lectures
	semesters, err := lecturesRepo.GetSemestersWithCourses(ctx)
	if err != nil {
		log.Fatalf("Get semesters: %v", err)
	}
	type TSCourse struct {
		Code string  `json:"code"`
		En   string  `json:"en"`
		Note *string `json:"note,omitempty"`
	}
	type TSSemester struct {
		Term    string     `json:"term"`
		Year    int        `json:"year"`
		Courses []TSCourse `json:"courses"`
	}
	var tsSemesters []TSSemester
	for _, s := range semesters {
		var tsCourses []TSCourse
		for _, c := range s.Courses {
			tsCourses = append(tsCourses, TSCourse{
				Code: c.Code,
				En:   c.NameEn,
				Note: c.Note,
			})
		}
		tsSemesters = append(tsSemesters, TSSemester{
			Term:    s.Term,
			Year:    s.Year,
			Courses: tsCourses,
		})
	}
	lecturesBytes, err := formatTSFile(`import { Semester } from "./types";`, "semesters", "Semester[]", tsSemesters)
	if err != nil {
		log.Fatalf("Format lectures.ts failed: %v", err)
	}
	if err := writeFileSafe(filepath.Join(*targetDir, "lectures.ts"), lecturesBytes); err != nil {
		log.Fatalf("Write lectures.ts failed: %v", err)
	}
	log.Println("✓ Exported lectures.ts")

	// 5. Standards
	standards, err := standardsRepo.GetStandardsBodiesWithProjects(ctx)
	if err != nil {
		log.Fatalf("Get standards bodies: %v", err)
	}
	type TSDoc struct {
		Title       string  `json:"title"`
		Ref         string  `json:"ref"`
		Status      string  `json:"status"`
		PublishedAt *string `json:"publishedAt,omitempty"`
	}
	type TSStandardProject struct {
		WG        string  `json:"wg"`
		Name      string  `json:"name"`
		Documents []TSDoc `json:"documents"`
	}
	type TSStandardsBody struct {
		Org      string              `json:"org"`
		Full     string              `json:"full"`
		Scope    string              `json:"scope"`
		Period   string              `json:"period"`
		Role     *string             `json:"role,omitempty"`
		Projects []TSStandardProject `json:"projects"`
	}
	var tsStandards []TSStandardsBody
	for _, b := range standards {
		var tsProjs []TSStandardProject
		for _, p := range b.Projects {
			var tsDocs []TSDoc
			for _, d := range p.Documents {
				tsDocs = append(tsDocs, TSDoc{
					Title:       d.Title,
					Ref:         d.DocRef,
					Status:      d.Status,
					PublishedAt: d.PublishedAt,
				})
			}
			tsProjs = append(tsProjs, TSStandardProject{
				WG:        p.WG,
				Name:      p.Name,
				Documents: tsDocs,
			})
		}
		tsStandards = append(tsStandards, TSStandardsBody{
			Org:      b.Org,
			Full:     b.FullName,
			Scope:    b.Scope,
			Period:   b.Period,
			Role:     b.Role,
			Projects: tsProjs,
		})
	}
	standardsBytes, err := formatTSFile(`import { StandardsBody } from "./types";`, "standardsBodies", "StandardsBody[]", tsStandards)
	if err != nil {
		log.Fatalf("Format standards.ts failed: %v", err)
	}
	if err := writeFileSafe(filepath.Join(*targetDir, "standards.ts"), standardsBytes); err != nil {
		log.Fatalf("Write standards.ts failed: %v", err)
	}
	log.Println("✓ Exported standards.ts")

	log.Println("=== All content successfully exported from SQLite! ===")
}
