package gen

import (
    _ "embed" // Пакет для встраивания содержимого файлов в бинарники Go, использовав откладку //go:embed
    "encoding/json" // Пакет для работы с JSON: декодирование и кодирование
    "errors"    // Пакет для создания и обработки ошибок
    "fmt"       // Пакет для форматированного ввода и вывода
    "io"        // Пакет для интерфейсов ввода и вывода
    "net/http"  // Пакет для HTTP-клиентов и серверов
    "text/template" // Пакет для обработки текстовых шаблонов
)

// Используем директиву //go:embed для встраивания содержимого файла шаблона в строку pipTmpl
// Встраивание файла tmpls/pip.tmpl.sh
//go:embed tmpls/pip.tmpl.sh
var pipTmpl string

// PipOptions содержит параметры, которые будут переданы в шаблон
type PipOptions struct {
    Name        string // Имя пакета
    Version     string // Версия пакета
    Description string // Описание пакета
}

// pypiAPIResponse представляет структуру ответа от API PyPI
type pypiAPIResponse struct {
    Info pypiInfo  `json:"info"` // Информация о пакете
    URLs []pypiURL `json:"urls"` // Список URL-адресов для загрузки пакета
}

// Метод SourceURL ищет и возвращает URL исходного distribution для пакета, если он существует
func (res pypiAPIResponse) SourceURL() (pypiURL, error) {
    for _, url := range res.URLs {
        if url.PackageType == "sdist" {
            return url, nil
        }
    }
    return pypiURL{}, errors.New("package doesn't have a source distribution")
}

// pypiInfo содержит основную информацию о пакете, такую как имя, версия и пр.
type pypiInfo struct {
    Name     string `json:"name"`
    Version  string `json:"version"`
    Summary  string `json:"summary"`
    Homepage string `json:"home_page"`
    License  string `json:"license"`
}

// pypiURL представляет информацию об одном из доступных для загрузки URL
type pypiURL struct {
    Digests     map[string]string `json:"digests"` // Контрольные суммы для файлов
    Filename    string            `json:"filename"` // Имя файла
    PackageType string            `json:"packagetype"` // Тип пакета (например sdist)
}

// Функция Pip загружает информацию о пакете из PyPI и использует шаблон для вывода информации
func Pip(w io.Writer, opts PipOptions) error {
    // Создаем новый шаблон с добавлением функций из FuncMap
    tmpl, err := template.New("pip").
        Funcs(funcs).
        Parse(pipTmpl)
    if err != nil {
        return err
    }

    // Формируем URL для запроса к PyPI на основании имени и версии пакета
    url := fmt.Sprintf(
        "https://pypi.org/pypi/%s/%s/json",
        opts.Name,
        opts.Version,
    )

    // Выполняем HTTP GET запрос к PyPI
    res, err := http.Get(url)
    if err != nil {
        return err
    }
    defer res.Body.Close() // Закрываем тело ответа после завершения работы
    if res.StatusCode != 200 {
        return fmt.Errorf("pypi: %s", res.Status)
    }

    // Раскодируем ответ JSON от PyPI в структуру pypiAPIResponse
    var resp pypiAPIResponse
    err = json.NewDecoder(res.Body).Decode(&resp)
    if err != nil {
        return err
    }

    // Если в opts указано описание, используем его вместо описания из PyPI
    if opts.Description != "" {
        resp.Info.Summary = opts.Description
    }

    // Выполняем шаблон с использованием данных из resp и записываем результат в w
    return tmpl.Execute(w, resp)
}