# Импорт необходимых библиотек
from aiohttp import web
import aiomysql
import aiohttp
import aiohttp_cors

# Конфигурация подключения к базе данных
DB_CONFIG = {
    'host': 'localhost',
    'port': 3306,
    'user': 'root',
    'password': '7GmCyoOL4zI6t2V0',
    'db': 'pos_bot',
    'charset': 'utf8mb4',
    'autocommit': True
}

# Асинхронная функция для инициализации пула подключений к базе данных
async def init_db_pool(app):
    app['db_pool'] = await aiomysql.create_pool(**DB_CONFIG)

# Асинхронная функция для завершения работы с пулом подключений к базе данных
async def close_db_pool(app):
    app['db_pool'].close()
    await app['db_pool'].wait_closed()


# Асинхронная функция для получения информации о книге
async def get_book(request):
    # Получение параметра запроса 'book_code'
    book_code = request.query.get('book_code', 0)
    # Преобразование параметра 'book_code' в целочисленное значение
    book_code = int(book_code)
    # Получение параметра запроса 'page', если он есть
    page = request.query.get('page', 1)
    # Преобразование параметра 'page' в целочисленное значение
    page = int(page)
    # Устанавливаем количество записей на одной странице
    items_per_page = 2
    offset = (page - 1) * items_per_page
    
    # Подключение к базе данных
    async with request.app['db_pool'].acquire() as conn:
        # Создание курсора для выполнения запросов к базе данных
        async with conn.cursor(aiomysql.DictCursor) as cursor:
            # Выполнение SQL-запроса для получения книги с кодом больше указанного
            await cursor.execute("""
                SELECT * FROM `popular_all`
                WHERE `book_code` > %s
                ORDER BY `book_code`
                ASC LIMIT %s OFFSET %s""", (book_code, items_per_page, offset))
            # Получение одной записи из результатов запроса
            books = await cursor.fetchall()

    # Возвращаем информацию о книгах в формате JSON
    return web.json_response({'books': books, 'page': page})


# Асинхронная функция для получения информации о новеллах
async def get_novel(request):
    # Получение параметра запроса 'book_code'
    book_code = request.query.get('book_code', 0)
    # Преобразование параметра 'book_code' в целочисленное значение
    book_code = int(book_code)
    # Получение параметра запроса 'page', если он есть
    page = request.query.get('page', 1)
    # Преобразование параметра 'page' в целочисленное значение
    page = int(page)
    # Устанавливаем количество записей на одной странице
    items_per_page = 2
    offset = (page - 1) * items_per_page
    
    # Подключение к базе данных
    async with request.app['db_pool'].acquire() as conn:
        # Создание курсора для выполнения запросов к базе данных
        async with conn.cursor(aiomysql.DictCursor) as cursor:
            # Выполнение SQL-запроса для получения книги с кодом больше указанного
            await cursor.execute("""
                SELECT * FROM `popular_all`
                WHERE `book_code` > %s
                AND `book_type` = 'новелла'
                ORDER BY `book_code`
                ASC LIMIT %s OFFSET %s""", (book_code, items_per_page, offset))
            # Получение одной записи из результатов запроса
            books = await cursor.fetchall()

    # Возвращаем информацию о книгах в формате JSON
    return web.json_response({'books': books, 'page': page})


# Асинхронная функция для получения информации о фанфиках
async def get_fanfic(request):
    # Получение параметра запроса 'book_code'
    book_code = request.query.get('book_code', 0)
    # Преобразование параметра 'book_code' в целочисленное значение
    book_code = int(book_code)
    # Получение параметра запроса 'page', если он есть
    page = request.query.get('page', 1)
    # Преобразование параметра 'page' в целочисленное значение
    page = int(page)
    # Устанавливаем количество записей на одной странице
    items_per_page = 2
    offset = (page - 1) * items_per_page
    
    # Подключение к базе данных
    async with request.app['db_pool'].acquire() as conn:
        # Создание курсора для выполнения запросов к базе данных
        async with conn.cursor(aiomysql.DictCursor) as cursor:
            # Выполнение SQL-запроса для получения книги с кодом больше указанного
            await cursor.execute("""
                SELECT * FROM `popular_all`
                WHERE `book_code` > %s
                AND `book_type` = 'фанфик'
                ORDER BY `book_code`
                ASC LIMIT %s OFFSET %s""", (book_code, items_per_page, offset))
            # Получение одной записи из результатов запроса
            books = await cursor.fetchall()

    # Возвращаем информацию о книгах в формате JSON
    return web.json_response({'books': books, 'page': page})


# ПОИСК
async def search(request):
    # Получаем поисковый запрос из параметров GET-запроса
    search_query = request.query.get('q', 0)
    # Получение параметра запроса 'page', если он есть
    page = request.query.get('page', 1)
    # Преобразование параметра 'page' в целочисленное значение
    page = int(page)
    # Устанавливаем количество записей на одной странице
    items_per_page = 2
    offset = (page - 1) * items_per_page

    # Подключение к базе данных
    async with request.app['db_pool'].acquire() as conn:
        # Создание курсора для выполнения запросов к базе данных
        async with conn.cursor(aiomysql.DictCursor) as cursor:
            # Выполняем поиск в базе данных по заданному запросу
            await cursor.execute("""
                SELECT * FROM `search`
                WHERE `title` LIKE %s
                LIMIT %s OFFSET %s""",
                ('%' + search_query + '%', items_per_page, offset))
            # Получаем все найденные записи
            results = await cursor.fetchall()

    # Возвращаем результаты в формате JSON
    return web.json_response({'results': results, 'page': page})


# ДОБАВЛЕНИЕ ОБЛОЖКИ
async def add_image_link(request):
    # Получаем данные
    params = await request.post()
    # Получаем book_code книги
    book_code = params.get('book_code')
    # Получаем ссылку на обложку
    image_link = params.get('image_link')

    # Подключение к базе данных
    async with request.app['db_pool'].acquire() as conn:
        # Создание курсора для выполнения запросов к базе данных
        async with conn.cursor() as cursor:
            # Проверка, не добавлена ли уже ссылка на изображение
            await cursor.execute("""
                SELECT art
                FROM book
                WHERE book_code = %s""",
                (book_code,))
            art_link = await cursor.fetchone()
            
            # Обновление записи, если в столбце art NULL
            if art_link and art_link[0] is None:
                await cursor.execute("""
                    UPDATE book
                    SET art = %s
                    WHERE book_code = %s""",
                    (image_link, book_code))
                await conn.commit()
                return web.Response(text="Изображение добавлено в базу данных.")
            else:
                return web.Response(text="Изображение уже существует.")


# Асинхронная функция для получения информации об авторе
async def get_author_info(request):
    # Получение параметра запроса 'author_code', если он есть
    author_code = request.query.get('author_code')
    # Преобразование параметра 'author_code' в целочисленное значение
    author_code = int(author_code)

    # Подключение к базе данных
    async with request.app['db_pool'].acquire() as conn:
        # Создание курсора для выполнения запросов к базе данных
        async with conn.cursor(aiomysql.DictCursor) as cursor:
            # Выбираем информацию об авторе
            await cursor.execute("""
                SELECT author_name, book_art
                FROM popular_all
                WHERE author_code = %s
                LIMIT 1""",
                (author_code,))
            author = await cursor.fetchone()

            # Если автора нет, отправляем ошибку
            if not author:
                return web.Response(text="Этого автора не существует.", status=404)

            # Теперь выбираем все книги этого автора
            await cursor.execute("""
                SELECT * FROM `popular_all`
                WHERE author_code = %s""",
                (author_code,))
            books = await cursor.fetchall()

    # Отправляем информацию об авторе и книгах в формате JSON
    return web.json_response({'author': author, 'books': books})

# Создание экземпляра приложения aiohttp
app = web.Application()

# Настройка сигналов для инициализации и завершения пула подключений
app.on_startup.append(init_db_pool)
app.on_cleanup.append(close_db_pool)

# Добавление маршрутов и обработчиков
app.add_routes([
    web.get('/get-books', get_book),
    web.get('/get-novel', get_novel),
    web.get('/get-fanfic', get_fanfic),
    web.get('/search', search),
    web.post('/add-image', add_image_link),
    web.get('/get-author', get_author_info)])

# Добавление статического маршрута для обслуживания файлов из указанной директории
app.router.add_static('/', path='/var/www/ranobepluskn_usr3/data/www/ranobeplusknigi.ru', name='static', show_index=True)


cors = aiohttp_cors.setup(app, defaults={
    "*": aiohttp_cors.ResourceOptions(
         allow_credentials=True,
         expose_headers="*",
         allow_headers="*"
         )
    })

for route in list(app.router.routes()):
    cors.add(route)

# Точка входа для запуска приложения
if __name__ == '__main__':
    web.run_app(app, host='46.30.42.17', port=8080)