package funding

import (
	"archive/zip"
	"bytes"
	"fmt"
	"io"
	"time"

	"github.com/jung-kurt/gofpdf"
	"github.com/xuri/excelize/v2"
)

// ExportService handles document generation
type ExportService struct{}

// NewExportService creates a new export service
func NewExportService() *ExportService {
	return &ExportService{}
}

// GenerateApplicationLetter generates the main application letter as PDF
func (s *ExportService) GenerateApplicationLetter(app *FundingApplication) ([]byte, error) {
	pdf := gofpdf.New("P", "mm", "A4", "")
	pdf.SetMargins(25, 25, 25)
	pdf.AddPage()

	// Header
	pdf.SetFont("Helvetica", "B", 14)
	pdf.Cell(0, 10, "Antrag auf Foerderung im Rahmen der digitalen Bildungsinfrastruktur")
	pdf.Ln(15)

	// Application number
	pdf.SetFont("Helvetica", "", 10)
	pdf.Cell(0, 6, fmt.Sprintf("Antragsnummer: %s", app.ApplicationNumber))
	pdf.Ln(6)
	pdf.Cell(0, 6, fmt.Sprintf("Datum: %s", time.Now().Format("02.01.2006")))
	pdf.Ln(15)

	// Section 1: Einleitung
	pdf.SetFont("Helvetica", "B", 12)
	pdf.Cell(0, 8, "1. Einleitung")
	pdf.Ln(10)
	pdf.SetFont("Helvetica", "", 10)

	if app.SchoolProfile != nil {
		pdf.MultiCell(0, 6, fmt.Sprintf(
			"Die %s (Schulnummer: %s) beantragt hiermit Foerdermittel aus dem Programm %s.\n\n"+
				"Schultraeger: %s\n"+
				"Schulform: %s\n"+
				"Schueleranzahl: %d\n"+
				"Lehrkraefte: %d",
			app.SchoolProfile.Name,
			app.SchoolProfile.SchoolNumber,
			app.FundingProgram,
			app.SchoolProfile.CarrierName,
			app.SchoolProfile.Type,
			app.SchoolProfile.StudentCount,
			app.SchoolProfile.TeacherCount,
		), "", "", false)
	}
	pdf.Ln(10)

	// Section 2: Projektziel
	pdf.SetFont("Helvetica", "B", 12)
	pdf.Cell(0, 8, "2. Projektziel")
	pdf.Ln(10)
	pdf.SetFont("Helvetica", "", 10)
	if app.ProjectPlan != nil {
		pdf.MultiCell(0, 6, app.ProjectPlan.Summary, "", "", false)
		pdf.Ln(5)
		pdf.MultiCell(0, 6, app.ProjectPlan.Goals, "", "", false)
	}
	pdf.Ln(10)

	// Section 3: Beschreibung der Massnahme
	pdf.SetFont("Helvetica", "B", 12)
	pdf.Cell(0, 8, "3. Beschreibung der Massnahme")
	pdf.Ln(10)
	pdf.SetFont("Helvetica", "", 10)
	if app.ProjectPlan != nil {
		pdf.MultiCell(0, 6, app.ProjectPlan.DidacticConcept, "", "", false)
	}
	pdf.Ln(10)

	// Section 4: Datenschutz & IT-Betrieb
	pdf.SetFont("Helvetica", "B", 12)
	pdf.Cell(0, 8, "4. Datenschutz & IT-Betrieb")
	pdf.Ln(10)
	pdf.SetFont("Helvetica", "", 10)
	if app.ProjectPlan != nil && app.ProjectPlan.DataProtection != "" {
		pdf.MultiCell(0, 6, app.ProjectPlan.DataProtection, "", "", false)
	}
	pdf.Ln(10)

	// Section 5: Kosten & Finanzierung
	pdf.SetFont("Helvetica", "B", 12)
	pdf.Cell(0, 8, "5. Kosten & Finanzierung")
	pdf.Ln(10)
	pdf.SetFont("Helvetica", "", 10)
	if app.Budget != nil {
		pdf.Cell(0, 6, fmt.Sprintf("Gesamtkosten: %.2f EUR", app.Budget.TotalCost))
		pdf.Ln(6)
		pdf.Cell(0, 6, fmt.Sprintf("Beantragter Foerderbetrag: %.2f EUR (%.0f%%)", app.Budget.RequestedFunding, app.Budget.FundingRate*100))
		pdf.Ln(6)
		pdf.Cell(0, 6, fmt.Sprintf("Eigenanteil: %.2f EUR", app.Budget.OwnContribution))
	}
	pdf.Ln(10)

	// Section 6: Laufzeit
	pdf.SetFont("Helvetica", "B", 12)
	pdf.Cell(0, 8, "6. Laufzeit")
	pdf.Ln(10)
	pdf.SetFont("Helvetica", "", 10)
	if app.Timeline != nil {
		pdf.Cell(0, 6, fmt.Sprintf("Projektbeginn: %s", app.Timeline.PlannedStart.Format("02.01.2006")))
		pdf.Ln(6)
		pdf.Cell(0, 6, fmt.Sprintf("Projektende: %s", app.Timeline.PlannedEnd.Format("02.01.2006")))
	}
	pdf.Ln(15)

	// Footer note
	pdf.SetFont("Helvetica", "I", 9)
	pdf.MultiCell(0, 5, "Hinweis: Dieser Antrag wurde mit dem Foerderantrag-Wizard von BreakPilot erstellt. "+
		"Die finale Pruefung und Einreichung erfolgt durch den Schultraeger.", "", "", false)

	var buf bytes.Buffer
	if err := pdf.Output(&buf); err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

// GenerateBudgetPlan generates the budget plan as XLSX
func (s *ExportService) GenerateBudgetPlan(app *FundingApplication) ([]byte, error) {
	f := excelize.NewFile()
	sheetName := "Kostenplan"
	f.SetSheetName("Sheet1", sheetName)

	// Header row
	headers := []string{
		"Pos.", "Kategorie", "Beschreibung", "Hersteller",
		"Anzahl", "Einzelpreis", "Gesamt", "Foerderfahig", "Finanzierung",
	}
	for i, h := range headers {
		cell, _ := excelize.CoordinatesToCellName(i+1, 1)
		f.SetCellValue(sheetName, cell, h)
	}

	// Style header
	headerStyle, _ := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{Bold: true},
		Fill: excelize.Fill{Type: "pattern", Color: []string{"#E0E0E0"}, Pattern: 1},
	})
	f.SetRowStyle(sheetName, 1, 1, headerStyle)

	// Data rows
	row := 2
	if app.Budget != nil {
		for i, item := range app.Budget.BudgetItems {
			f.SetCellValue(sheetName, fmt.Sprintf("A%d", row), i+1)
			f.SetCellValue(sheetName, fmt.Sprintf("B%d", row), string(item.Category))
			f.SetCellValue(sheetName, fmt.Sprintf("C%d", row), item.Description)
			f.SetCellValue(sheetName, fmt.Sprintf("D%d", row), item.Manufacturer)
			f.SetCellValue(sheetName, fmt.Sprintf("E%d", row), item.Quantity)
			f.SetCellValue(sheetName, fmt.Sprintf("F%d", row), item.UnitPrice)
			f.SetCellValue(sheetName, fmt.Sprintf("G%d", row), item.TotalPrice)
			fundable := "Nein"
			if item.IsFundable {
				fundable = "Ja"
			}
			f.SetCellValue(sheetName, fmt.Sprintf("H%d", row), fundable)
			f.SetCellValue(sheetName, fmt.Sprintf("I%d", row), item.FundingSource)
			row++
		}

		// Summary rows
		row += 2
		f.SetCellValue(sheetName, fmt.Sprintf("F%d", row), "Gesamtkosten:")
		f.SetCellValue(sheetName, fmt.Sprintf("G%d", row), app.Budget.TotalCost)
		row++
		f.SetCellValue(sheetName, fmt.Sprintf("F%d", row), "Foerderbetrag:")
		f.SetCellValue(sheetName, fmt.Sprintf("G%d", row), app.Budget.RequestedFunding)
		row++
		f.SetCellValue(sheetName, fmt.Sprintf("F%d", row), "Eigenanteil:")
		f.SetCellValue(sheetName, fmt.Sprintf("G%d", row), app.Budget.OwnContribution)
	}

	// Set column widths
	f.SetColWidth(sheetName, "A", "A", 6)
	f.SetColWidth(sheetName, "B", "B", 15)
	f.SetColWidth(sheetName, "C", "C", 35)
	f.SetColWidth(sheetName, "D", "D", 15)
	f.SetColWidth(sheetName, "E", "E", 8)
	f.SetColWidth(sheetName, "F", "F", 12)
	f.SetColWidth(sheetName, "G", "G", 12)
	f.SetColWidth(sheetName, "H", "H", 12)
	f.SetColWidth(sheetName, "I", "I", 15)

	// Add currency format
	currencyStyle, _ := f.NewStyle(&excelize.Style{
		NumFmt: 44, // Currency format
	})
	f.SetColStyle(sheetName, "F", currencyStyle)
	f.SetColStyle(sheetName, "G", currencyStyle)

	var buf bytes.Buffer
	if err := f.Write(&buf); err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

// GenerateDataProtectionConcept generates the data protection concept as PDF
func (s *ExportService) GenerateDataProtectionConcept(app *FundingApplication) ([]byte, error) {
	pdf := gofpdf.New("P", "mm", "A4", "")
	pdf.SetMargins(25, 25, 25)
	pdf.AddPage()

	// Header
	pdf.SetFont("Helvetica", "B", 14)
	pdf.Cell(0, 10, "Datenschutz- und Betriebskonzept")
	pdf.Ln(15)

	pdf.SetFont("Helvetica", "", 10)
	pdf.Cell(0, 6, fmt.Sprintf("Antragsnummer: %s", app.ApplicationNumber))
	pdf.Ln(6)
	if app.SchoolProfile != nil {
		pdf.Cell(0, 6, fmt.Sprintf("Schule: %s", app.SchoolProfile.Name))
	}
	pdf.Ln(15)

	// Section: Lokale Verarbeitung
	pdf.SetFont("Helvetica", "B", 12)
	pdf.Cell(0, 8, "1. Grundsaetze der Datenverarbeitung")
	pdf.Ln(10)
	pdf.SetFont("Helvetica", "", 10)

	if app.ProjectPlan != nil && app.ProjectPlan.DataProtection != "" {
		pdf.MultiCell(0, 6, app.ProjectPlan.DataProtection, "", "", false)
	} else {
		pdf.MultiCell(0, 6, "Das Projekt setzt auf eine vollstaendig lokale Datenverarbeitung:\n\n"+
			"- Alle Daten werden ausschliesslich auf den schuleigenen Systemen verarbeitet\n"+
			"- Keine Uebermittlung personenbezogener Daten an externe Dienste\n"+
			"- Keine Cloud-Speicherung sensibler Daten\n"+
			"- Betrieb im Verantwortungsbereich der Schule", "", "", false)
	}
	pdf.Ln(10)

	// Section: Technische Massnahmen
	pdf.SetFont("Helvetica", "B", 12)
	pdf.Cell(0, 8, "2. Technische und organisatorische Massnahmen")
	pdf.Ln(10)
	pdf.SetFont("Helvetica", "", 10)
	pdf.MultiCell(0, 6, "Folgende TOMs werden umgesetzt:\n\n"+
		"- Zugriffskontrolle ueber schuleigene Benutzerverwaltung\n"+
		"- Verschluesselte Datenspeicherung\n"+
		"- Regelmaessige Sicherheitsupdates\n"+
		"- Protokollierung von Zugriffen\n"+
		"- Automatische Loeschung nach definierten Fristen", "", "", false)
	pdf.Ln(10)

	// Section: Betriebskonzept
	pdf.SetFont("Helvetica", "B", 12)
	pdf.Cell(0, 8, "3. Betriebskonzept")
	pdf.Ln(10)
	pdf.SetFont("Helvetica", "", 10)
	if app.ProjectPlan != nil && app.ProjectPlan.MaintenancePlan != "" {
		pdf.MultiCell(0, 6, app.ProjectPlan.MaintenancePlan, "", "", false)
	} else {
		pdf.MultiCell(0, 6, "Der laufende Betrieb wird wie folgt sichergestellt:\n\n"+
			"- Schulung des technischen Personals\n"+
			"- Dokumentierte Betriebsverfahren\n"+
			"- Regelmaessige Wartung und Updates\n"+
			"- Definierte Ansprechpartner", "", "", false)
	}

	var buf bytes.Buffer
	if err := pdf.Output(&buf); err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

// GenerateExportBundle generates a ZIP file with all documents
func (s *ExportService) GenerateExportBundle(app *FundingApplication) ([]byte, error) {
	var buf bytes.Buffer
	zipWriter := zip.NewWriter(&buf)

	// Generate and add application letter
	letter, err := s.GenerateApplicationLetter(app)
	if err == nil {
		w, _ := zipWriter.Create(fmt.Sprintf("%s_Antragsschreiben.pdf", app.ApplicationNumber))
		w.Write(letter)
	}

	// Generate and add budget plan
	budget, err := s.GenerateBudgetPlan(app)
	if err == nil {
		w, _ := zipWriter.Create(fmt.Sprintf("%s_Kostenplan.xlsx", app.ApplicationNumber))
		w.Write(budget)
	}

	// Generate and add data protection concept
	dp, err := s.GenerateDataProtectionConcept(app)
	if err == nil {
		w, _ := zipWriter.Create(fmt.Sprintf("%s_Datenschutzkonzept.pdf", app.ApplicationNumber))
		w.Write(dp)
	}

	// Add attachments
	for _, attachment := range app.Attachments {
		// Read attachment from storage and add to ZIP
		// This would need actual file system access
		_ = attachment
	}

	if err := zipWriter.Close(); err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

// ExportDocument represents a generated document
type GeneratedDocument struct {
	Name     string
	Type     string // pdf, xlsx, docx
	Content  []byte
	MimeType string
}

// GenerateAllDocuments generates all documents for an application
func (s *ExportService) GenerateAllDocuments(app *FundingApplication) ([]GeneratedDocument, error) {
	var docs []GeneratedDocument

	// Application letter
	letter, err := s.GenerateApplicationLetter(app)
	if err == nil {
		docs = append(docs, GeneratedDocument{
			Name:     fmt.Sprintf("%s_Antragsschreiben.pdf", app.ApplicationNumber),
			Type:     "pdf",
			Content:  letter,
			MimeType: "application/pdf",
		})
	}

	// Budget plan
	budget, err := s.GenerateBudgetPlan(app)
	if err == nil {
		docs = append(docs, GeneratedDocument{
			Name:     fmt.Sprintf("%s_Kostenplan.xlsx", app.ApplicationNumber),
			Type:     "xlsx",
			Content:  budget,
			MimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
		})
	}

	// Data protection concept
	dp, err := s.GenerateDataProtectionConcept(app)
	if err == nil {
		docs = append(docs, GeneratedDocument{
			Name:     fmt.Sprintf("%s_Datenschutzkonzept.pdf", app.ApplicationNumber),
			Type:     "pdf",
			Content:  dp,
			MimeType: "application/pdf",
		})
	}

	return docs, nil
}

// WriteZipToWriter writes all documents to a zip writer
func (s *ExportService) WriteZipToWriter(app *FundingApplication, w io.Writer) error {
	zipWriter := zip.NewWriter(w)
	defer zipWriter.Close()

	docs, err := s.GenerateAllDocuments(app)
	if err != nil {
		return err
	}

	for _, doc := range docs {
		f, err := zipWriter.Create(doc.Name)
		if err != nil {
			continue
		}
		f.Write(doc.Content)
	}

	return nil
}
