package importer

import (
	"archive/zip"
	"context"
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"

	"gitea.mrixs.me/minecraft-platform/backend/internal/models"
)

// ModrinthImporter реализует импорт для сборок Modrinth (.mrpack).
type ModrinthImporter struct {
	StoragePath string
	HTTPClient  *http.Client
}

// NewModrinthImporter создает новый экземпляр импортера.
func NewModrinthImporter(storagePath string) *ModrinthImporter {
	return &ModrinthImporter{
		StoragePath: storagePath,
		HTTPClient:  &http.Client{Timeout: 10 * time.Minute},
	}
}

// downloadAndProcessFile скачивает файл и обрабатывает его.
func (i *ModrinthImporter) downloadAndProcessFile(url string) (hash string, size int64, err error) {
	req, err := http.NewRequestWithContext(context.Background(), "GET", url, nil)
	if err != nil {
		return "", 0, err
	}

	resp, err := i.HTTPClient.Do(req)
	if err != nil {
		return "", 0, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return "", 0, fmt.Errorf("bad status downloading file: %s", resp.Status)
	}

	baseImporter := SimpleZipImporter{StoragePath: i.StoragePath}
	return baseImporter.processFile(resp.Body)
}

// Import реализует основной метод интерфейса ModpackImporter.
func (i *ModrinthImporter) Import(zipPath string) ([]models.ModpackFile, error) {
	r, err := zip.OpenReader(zipPath)
	if err != nil {
		return nil, err
	}
	defer r.Close()

	// 1. Ищем и парсим modrinth.index.json
	var indexFile *zip.File
	for _, f := range r.File {
		if f.Name == "modrinth.index.json" {
			indexFile = f
			break
		}
	}

	if indexFile == nil {
		return nil, fmt.Errorf("modrinth.index.json not found in archive")
	}

	idxReader, err := indexFile.Open()
	if err != nil {
		return nil, err
	}
	defer idxReader.Close()

	var index ModrinthIndex
	if err := json.NewDecoder(idxReader).Decode(&index); err != nil {
		return nil, fmt.Errorf("failed to parse modrinth.index.json: %w", err)
	}

	var files []models.ModpackFile

	// 2. Обрабатываем файлы из индекса (скачиваем их)
	for _, modFile := range index.Files {
		// Пропускаем серверные файлы, которые не нужны клиенту?
		// В ТЗ сказано про "клиент", но обычно лаунчер качает всё, что нужно клиенту.
		// env.client != "unsupported" (обычно "required" или "optional")
		if modFile.Env.Client == "unsupported" {
			continue
		}

		if len(modFile.Downloads) == 0 {
			log.Printf("Modrinth Importer: WARN - No download URLs for file '%s', skipping.", modFile.Path)
			continue
		}

		// Используем первый доступный URL
		downloadURL := modFile.Downloads[0]

		log.Printf("Modrinth Importer: Downloading '%s' from %s", modFile.Path, downloadURL)

		// Скачиваем файл и пересчитываем его хеш/размер (и сохраняем локально, если нужно)
		// Важно: Modrinth дает хеши в индексе. Мы могли бы использовать их, но наша система
		// построена на том, что мы храним файлы у себя. Поэтому нам всё равно нужно скачать их
		// и сохранить в наше хранилище. Метод downloadAndProcessFile делает именно это.
		hash, size, err := i.downloadAndProcessFile(downloadURL)
		if err != nil {
			log.Printf("Modrinth Importer: WARN - Failed to download/process '%s': %v", modFile.Path, err)
			continue
		}

		// Сверка хеша для надежности (опционально, но полезно)
		if modFile.Hashes.SHA1 != "" && modFile.Hashes.SHA1 != hash {
			log.Printf("Modrinth Importer: WARN - Hash mismatch for '%s'. Index SHA1: %s, Calculated: %s", modFile.Path, modFile.Hashes.SHA1, hash)
			// Можно решить: падать с ошибкой или доверять тому, что скачали.
			// Пока просто предупреждаем.
		}

		files = append(files, models.ModpackFile{
			RelativePath: modFile.Path,
			FileHash:     hash,
			FileSize:     size,
			DownloadURL:  downloadURL,
		})
	}

	// 3. Обрабатываем overrides
	baseImporter := SimpleZipImporter{StoragePath: i.StoragePath}
	for _, f := range r.File {
		// В .mrpack файлы для копирования лежат в папке "overrides/" (как правило)
		// Спецификация говорит, что папка может называться иначе? Нет, обычно overrides.
		// Но лучше проверить все папки, кроме системных.
		// Спецификация Modrinth: "Files that are included in the modpack archive are located in the overrides directory."

		prefix := "overrides/"
		if strings.HasPrefix(f.Name, prefix) && !f.FileInfo().IsDir() {
			fileReader, err := f.Open()
			if err != nil {
				return nil, err
			}

			hash, size, err := baseImporter.processFile(fileReader)
			if err != nil {
				fileReader.Close()
				return nil, err
			}
			fileReader.Close()

			relativePath := strings.TrimPrefix(f.Name, prefix)
			files = append(files, models.ModpackFile{
				RelativePath: relativePath,
				FileHash:     hash,
				FileSize:     size,
			})
		}
	}

	return files, nil
}
