/*
 * Copyright (c) 2025-2026, Антон Аксенов
 * This file is part of iptvc project
 * MIT License: https://git.axenov.dev/IPTV/iptvc/src/branch/master/LICENSE
 */

package web

import (
	"axenov/iptv-checker/app"
	"embed"
	"encoding/json"
	"io/fs"
	"net/http"
)

//go:embed swagger
var swaggerFS embed.FS

//go:embed static
var staticFS embed.FS

// handleOpenAPISpec — отдаёт динамически сгенерированную OpenAPI 3.0 спецификацию
func (s *Server) handleOpenAPISpec(w http.ResponseWriter, r *http.Request) {
	spec := s.generateOpenAPISpec()
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(spec)
}

// swaggerFileServer раздаёт встроенные файлы Swagger UI (CSS, JS, HTML)
var swaggerFileServer http.Handler

// staticFileServer раздаёт встроенные статические файлы (JS, CSS)
var staticFileServer http.Handler

func init() {
	sub, err := fs.Sub(swaggerFS, "swagger")
	if err != nil {
		panic("cannot create sub-FS for swagger: " + err.Error())
	}
	swaggerFileServer = http.FileServer(http.FS(sub))

	staticSub, err := fs.Sub(staticFS, "static")
	if err != nil {
		panic("cannot create sub-FS for static: " + err.Error())
	}
	staticFileServer = http.FileServer(http.FS(staticSub))
}

// generateOpenAPISpec строит OpenAPI 3.0.3 спецификацию динамически
func (s *Server) generateOpenAPISpec() map[string]interface{} {
	return map[string]interface{}{
		"openapi": "3.0.3",
		"info": map[string]interface{}{
			"title":       s.cfg.Site.Title + " API",
			"version":     app.VERSION,
			"description": "API для проверки IPTV-плейлистов и доступности каналов.",
			"license": map[string]interface{}{
				"name": "MIT",
				"url":  "https://git.axenov.dev/IPTV/iptvc/src/branch/master/LICENSE",
			},
		},
		"servers": []map[string]interface{}{
			{
				"url":         s.cfg.Site.BaseUrl,
				"description": "Текущий сервер",
			},
		},
		"paths": map[string]interface{}{
			"/api/playlists": map[string]interface{}{
				"get": map[string]interface{}{
					"tags":        []string{"Playlists"},
					"summary":     "Список плейлистов",
					"description": "Возвращает список всех плейлистов из ini-файла с результатами проверки.",
					"responses": map[string]interface{}{
						"200": map[string]interface{}{
							"description": "Список плейлистов",
							"content": map[string]interface{}{
								"application/json": map[string]interface{}{
									"schema": map[string]interface{}{"$ref": "#/components/schemas/PlaylistListResponse"},
								},
							},
						},
						"500": map[string]interface{}{
							"description": "Ошибка загрузки плейлистов",
							"content": map[string]interface{}{
								"application/json": map[string]interface{}{
									"schema": map[string]interface{}{"$ref": "#/components/schemas/ErrorResponse"},
								},
							},
						},
					},
				},
			},
			"/api/playlists/{code}": map[string]interface{}{
				"get": map[string]interface{}{
					"tags":        []string{"Playlists"},
					"summary":     "Информация о плейлисте",
					"description": "Возвращает информацию о плейлисте по его коду, включая группы, атрибуты и результаты проверки.",
					"parameters": []map[string]interface{}{
						{
							"name":        "code",
							"in":          "path",
							"required":    true,
							"description": "Код плейлиста (из ini-файла)",
							"schema":      map[string]interface{}{"type": "string"},
						},
					},
					"responses": map[string]interface{}{
						"200": map[string]interface{}{
							"description": "Информация о плейлисте",
							"content": map[string]interface{}{
								"application/json": map[string]interface{}{
									"schema": map[string]interface{}{"$ref": "#/components/schemas/PlaylistResponse"},
								},
							},
						},
						"400": map[string]interface{}{
							"description": "Код плейлиста не передан",
							"content": map[string]interface{}{
								"application/json": map[string]interface{}{
									"schema": map[string]interface{}{"$ref": "#/components/schemas/ErrorResponse"},
								},
							},
						},
						"404": map[string]interface{}{
							"description": "Плейлист не найден",
							"content": map[string]interface{}{
								"application/json": map[string]interface{}{
									"schema": map[string]interface{}{"$ref": "#/components/schemas/ErrorResponse"},
								},
							},
						},
					},
				},
			},
			"/api/playlists/{code}/channels": map[string]interface{}{
				"get": map[string]interface{}{
					"tags":        []string{"Playlists"},
					"summary":     "Каналы плейлиста",
					"description": "Возвращает каналы плейлиста по его коду.",
					"parameters": []map[string]interface{}{
						{
							"name":        "code",
							"in":          "path",
							"required":    true,
							"description": "Код плейлиста (из ini-файла)",
							"schema":      map[string]interface{}{"type": "string"},
						},
					},
					"responses": map[string]interface{}{
						"200": map[string]interface{}{
							"description": "Каналы плейлиста",
							"content": map[string]interface{}{
								"application/json": map[string]interface{}{
									"schema": map[string]interface{}{"$ref": "#/components/schemas/ChannelListResponse"},
								},
							},
						},
						"400": map[string]interface{}{
							"description": "Код плейлиста не передан",
							"content": map[string]interface{}{
								"application/json": map[string]interface{}{
									"schema": map[string]interface{}{"$ref": "#/components/schemas/ErrorResponse"},
								},
							},
						},
						"404": map[string]interface{}{
							"description": "Плейлист не найден",
							"content": map[string]interface{}{
								"application/json": map[string]interface{}{
									"schema": map[string]interface{}{"$ref": "#/components/schemas/ErrorResponse"},
								},
							},
						},
					},
				},
			},
			"/api/version": map[string]interface{}{
				"get": map[string]interface{}{
					"tags":        []string{"System"},
					"summary":     "Версии компонентов",
					"description": "Возвращает версию iptvc и (при наличии) версию кеша.",
					"responses": map[string]interface{}{
						"200": map[string]interface{}{
							"description": "Информация о версиях",
							"content": map[string]interface{}{
								"application/json": map[string]interface{}{
									"schema": map[string]interface{}{"$ref": "#/components/schemas/VersionResponse"},
								},
							},
						},
					},
				},
			},
			"/api/health": map[string]interface{}{
				"get": map[string]interface{}{
					"tags":        []string{"System"},
					"summary":     "Состояние сервиса",
					"description": "Возвращает состояние подключения к кешу и путь к ini-файлу.",
					"responses": map[string]interface{}{
						"200": map[string]interface{}{
							"description": "Состояние сервиса",
							"content": map[string]interface{}{
								"application/json": map[string]interface{}{
									"schema": map[string]interface{}{"$ref": "#/components/schemas/HealthResponse"},
								},
							},
						},
					},
				},
			},
			"/api/stats": map[string]interface{}{
				"get": map[string]interface{}{
					"tags":        []string{"Statistics"},
					"summary":     "Статистика",
					"description": "Возвращает агрегированную статистику по плейлистам и каналам.",
					"responses": map[string]interface{}{
						"200": map[string]interface{}{
							"description": "Статистика",
							"content": map[string]interface{}{
								"application/json": map[string]interface{}{
									"schema": map[string]interface{}{"$ref": "#/components/schemas/StatsResponse"},
								},
							},
						},
						"500": map[string]interface{}{
							"description": "Ошибка загрузки плейлистов",
							"content": map[string]interface{}{
								"application/json": map[string]interface{}{
									"schema": map[string]interface{}{"$ref": "#/components/schemas/ErrorResponse"},
								},
							},
						},
					},
				},
			},
		},
		"components": map[string]interface{}{
			"schemas": map[string]interface{}{
				"PlaylistListResponse": map[string]interface{}{
					"type":        "object",
					"description": "Список плейлистов",
					"properties": map[string]interface{}{
						"timestamp": map[string]interface{}{"type": "integer", "description": "UNIX timestamp ответа"},
						"items": map[string]interface{}{
							"type":        "array",
							"items":       map[string]interface{}{"$ref": "#/components/schemas/Playlist"},
							"description": "Массив плейлистов",
						},
					},
				},
				"PlaylistResponse": map[string]interface{}{
					"type":        "object",
					"description": "Информация о плейлисте с результатами проверки",
					"allOf": []map[string]interface{}{
						{"$ref": "#/components/schemas/Playlist"},
					},
				},
				"Playlist": map[string]interface{}{
					"type":        "object",
					"description": "Информация о плейлисте",
					"properties": map[string]interface{}{
						"code":        map[string]interface{}{"type": "string", "description": "Код плейлиста"},
						"name":        map[string]interface{}{"type": "string", "description": "Название плейлиста"},
						"description": map[string]interface{}{"type": "string", "description": "Описание плейлиста"},
						"url":         map[string]interface{}{"type": "string", "description": "URL плейлиста"},
						"source":      map[string]interface{}{"type": "string", "description": "Источник плейлиста"},
						"isOnline": map[string]interface{}{
							"type":        "boolean",
							"nullable":    true,
							"description": "Доступность плейлиста (null если не проверялся)",
						},
						"onlineCount":  map[string]interface{}{"type": "integer", "description": "Количество рабочих каналов"},
						"offlineCount": map[string]interface{}{"type": "integer", "description": "Количество нерабочих каналов"},
						"checkedAt":    map[string]interface{}{"type": "integer", "description": "UNIX timestamp последней проверки"},
						"content": map[string]interface{}{
							"type":        "string",
							"description": "Содержимое плейлиста (только для оффлайн-плейлистов)",
						},
						"attributes": map[string]interface{}{
							"type":        "array",
							"items":       map[string]interface{}{"$ref": "#/components/schemas/Attribute"},
							"description": "Атрибуты тега #EXTM3U",
						},
						"groups": map[string]interface{}{
							"type":        "array",
							"items":       map[string]interface{}{"$ref": "#/components/schemas/Group"},
							"description": "Группы каналов",
						},
						"tags": map[string]interface{}{
							"type":        "array",
							"items":       map[string]interface{}{"type": "string"},
							"description": "Теги плейлиста",
						},
					},
				},
				"ChannelListResponse": map[string]interface{}{
					"type":        "object",
					"description": "Список каналов плейлиста",
					"properties": map[string]interface{}{
						"timestamp": map[string]interface{}{"type": "integer", "description": "UNIX timestamp ответа"},
						"items": map[string]interface{}{
							"type":        "array",
							"items":       map[string]interface{}{"$ref": "#/components/schemas/Channel"},
							"description": "Массив каналов",
						},
					},
				},
				"Channel": map[string]interface{}{
					"type":        "object",
					"description": "Информация о канале и статусе его проверки",
					"properties": map[string]interface{}{
						"id":       map[string]interface{}{"type": "string", "description": "MD5-хэш URL канала"},
						"title":    map[string]interface{}{"type": "string", "description": "Название канала"},
						"url":      map[string]interface{}{"type": "string", "description": "URL потока канала"},
						"groupId":  map[string]interface{}{"type": "string", "description": "MD5-хэш названия группы"},
						"hasToken": map[string]interface{}{"type": "boolean", "description": "Признак наличия токена/ключа в URL"},
						"attributes": map[string]interface{}{
							"type":        "array",
							"items":       map[string]interface{}{"$ref": "#/components/schemas/Attribute"},
							"description": "Атрибуты тега #EXTINF",
						},
						"status":      map[string]interface{}{"type": "integer", "description": "HTTP-код статуса"},
						"isOnline":    map[string]interface{}{"type": "boolean", "description": "Доступность канала (status < 400)"},
						"error":       map[string]interface{}{"type": "string", "description": "Текст ошибки"},
						"contentType": map[string]interface{}{"type": "string", "description": "MIME-тип ответа"},
						"tags": map[string]interface{}{
							"type":        "array",
							"items":       map[string]interface{}{"type": "string"},
							"description": "Теги канала",
						},
						"checkedAt": map[string]interface{}{"type": "integer", "description": "UNIX timestamp проверки"},
					},
				},
				"Group": map[string]interface{}{
					"type":        "object",
					"description": "Группа каналов",
					"properties": map[string]interface{}{
						"id":   map[string]interface{}{"type": "string", "description": "MD5-хэш названия группы"},
						"name": map[string]interface{}{"type": "string", "description": "Название группы"},
						"attributes": map[string]interface{}{
							"type":        "array",
							"items":       map[string]interface{}{"$ref": "#/components/schemas/Attribute"},
							"description": "Атрибуты тега #EXTGRP",
						},
					},
				},
				"Attribute": map[string]interface{}{
					"type":        "object",
					"description": "Именованный атрибут тега",
					"properties": map[string]interface{}{
						"name":  map[string]interface{}{"type": "string", "description": "Имя атрибута"},
						"value": map[string]interface{}{"type": "string", "description": "Значение атрибута"},
					},
				},
				"VersionResponse": map[string]interface{}{
					"type":        "object",
					"description": "Информация о версиях компонентов",
					"properties": map[string]interface{}{
						"timestamp": map[string]interface{}{"type": "integer", "description": "UNIX timestamp ответа"},
						"iptvc":     map[string]interface{}{"type": "string", "description": "Версия iptvc"},
						"cache": map[string]interface{}{
							"type":        "string",
							"description": "Версия кеша (если подключён)",
						},
					},
				},
				"HealthResponse": map[string]interface{}{
					"type":        "object",
					"description": "Состояние сервиса",
					"properties": map[string]interface{}{
						"timestamp": map[string]interface{}{"type": "integer", "description": "UNIX timestamp ответа"},
						"cache": map[string]interface{}{
							"type":        "object",
							"description": "Состояние подключения к кешу",
							"properties": map[string]interface{}{
								"isConnected": map[string]interface{}{"type": "boolean", "description": "Подключение установлено"},
							},
						},
						"iniFile": map[string]interface{}{
							"type":        "object",
							"description": "Информация об ini-файле",
							"properties": map[string]interface{}{
								"path": map[string]interface{}{"type": "string", "description": "Путь к playlists.ini"},
							},
						},
					},
				},
				"StatsResponse": map[string]interface{}{
					"type":        "object",
					"description": "Агрегированная статистика",
					"properties": map[string]interface{}{
						"timestamp": map[string]interface{}{"type": "integer", "description": "UNIX timestamp ответа"},
						"playlists": map[string]interface{}{
							"type":        "object",
							"description": "Статистика по плейлистам",
							"properties": map[string]interface{}{
								"all":        map[string]interface{}{"type": "integer"},
								"online":     map[string]interface{}{"type": "integer"},
								"offline":    map[string]interface{}{"type": "integer"},
								"unknown":    map[string]interface{}{"type": "integer"},
								"adult":      map[string]interface{}{"type": "integer"},
								"hasCatchup": map[string]interface{}{"type": "integer"},
								"hasTvg":     map[string]interface{}{"type": "integer"},
								"groupped":   map[string]interface{}{"type": "integer"},
								"latest": map[string]interface{}{
									"type": "object",
									"properties": map[string]interface{}{
										"code":    map[string]interface{}{"type": "string"},
										"time":    map[string]interface{}{"type": "integer"},
										"timeFmt": map[string]interface{}{"type": "string"},
									},
								},
							},
						},
						"channels": map[string]interface{}{
							"type":        "object",
							"description": "Статистика по каналам",
							"properties": map[string]interface{}{
								"all":     map[string]interface{}{"type": "integer"},
								"online":  map[string]interface{}{"type": "integer"},
								"offline": map[string]interface{}{"type": "integer"},
								"adult":   map[string]interface{}{"type": "integer"},
							},
						},
					},
				},
				"ErrorResponse": map[string]interface{}{
					"type":        "object",
					"description": "Ошибка",
					"properties": map[string]interface{}{
						"timestamp": map[string]interface{}{"type": "integer", "description": "UNIX timestamp ответа"},
						"error": map[string]interface{}{
							"type": "object",
							"properties": map[string]interface{}{
								"message": map[string]interface{}{"type": "string", "description": "Текст ошибки"},
							},
						},
					},
				},
			},
		},
	}
}
