// Copyright 2026 Moko Consulting <hello@mokoconsulting.tech>
// SPDX-License-Identifier: GPL-3.0-or-later

package release

import (
	"bytes"
	"context"
	"crypto/sha256"
	"fmt"
	"io"
	"strings"

	repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
	"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/log"
	"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/storage"
	attachment_service "code.mokoconsulting.tech/MokoConsulting/MokoGitea/services/attachment"
)

// GenerateReleaseChecksums computes SHA256 checksums for all attachments
// on a release and creates a [filename].sha256 file for each one.
func GenerateReleaseChecksums(ctx context.Context, rel *repo_model.Release) error {
	if err := repo_model.GetReleaseAttachments(ctx, rel); err != nil {
		return fmt.Errorf("GetReleaseAttachments: %w", err)
	}

	if len(rel.Attachments) == 0 {
		return nil
	}

	// Remove existing .sha256 files
	for _, a := range rel.Attachments {
		if strings.HasSuffix(a.Name, ".sha256") {
			if err := repo_model.DeleteAttachment(ctx, a, true); err != nil {
				log.Warn("Failed to delete old %s: %v", a.Name, err)
			}
		}
	}

	// Compute SHA256 for each non-checksum attachment and create individual .sha256 files
	created := 0
	for _, a := range rel.Attachments {
		if strings.HasSuffix(a.Name, ".sha256") {
			continue
		}

		fr, err := storage.Attachments.Open(a.RelativePath())
		if err != nil {
			log.Warn("Cannot open attachment %s for checksumming: %v", a.Name, err)
			continue
		}

		h := sha256.New()
		if _, err := io.Copy(h, fr); err != nil {
			fr.Close()
			log.Warn("Cannot read attachment %s for checksumming: %v", a.Name, err)
			continue
		}
		fr.Close()

		checksumContent := fmt.Sprintf("%x  %s\n", h.Sum(nil), a.Name)
		checksumReader := bytes.NewBufferString(checksumContent)

		checksumAttach := &repo_model.Attachment{
			RepoID:    rel.RepoID,
			ReleaseID: rel.ID,
			Name:      a.Name + ".sha256",
		}

		if _, err := attachment_service.NewAttachment(ctx, checksumAttach, checksumReader, int64(len(checksumContent))); err != nil {
			log.Warn("Failed to create %s: %v", checksumAttach.Name, err)
			continue
		}
		created++
	}

	if created > 0 {
		log.Info("Generated %d .sha256 checksum files for release %s (repo %d)", created, rel.TagName, rel.RepoID)
	}
	return nil
}
