import { Request, Response } from 'express';
import axios from "axios";
import path from "path";
import { prisma } from '../../../lib/prisma';
import { Prisma } from '@prisma/client';
import { AuthRequest } from '../../../middleware/auth';
import { checkPermission } from '../../../utils/permissions';
import { logger } from '../../../config/logger';
import { Article } from "../../../types";
import { uploadBufferToS3 } from "../../../services/s3Service";
import { AuthorRole } from "@prisma/client";


const DEFAULT_COVER_IMAGE = '/images/cover-placeholder.webp';

export async function getArticle(req: Request, res: Response) : Promise<void> {
  try {
    const article = await prisma.article.findUnique({
      where: { id: req.params.id },
      include: {
        authors: {
          include: {
            author: {
              select: {
                id: true,
                displayName: true,
                avatarUrl: true,
                email: true,
                order: true,
              },
            },
          },
        },
        gallery: {
          orderBy: {order: "asc"}, // Сортировка изображений по порядку
          select: {
            id: true,
            url: true,
            caption: true,
            alt: true,
            width: true,
            height: true,
            size: true,
            format: true,
            order: true, // Добавляем порядок сортировки
          },
        }
      }
    });

    if (!article) {
      logger.warn(`Статья не найдена: ${req.params.id}`);
      res.status(404).json({ error: 'Статья не найдена' });
      return
    }

    res.json(article);
  } catch (error) {
    logger.error('Error fetching article:', error);
    res.status(500).json({ error: 'Server error' });
  }
}

export async function createArticle(req: AuthRequest, res: Response) : Promise<void> {
  try {
    const { title, excerpt, content, categoryId, cityId, coverImage, readTime } = req.body;

    if (!req.user) {
      logger.warn('Пользователь не вошел в систему');
      res.status(401).json({ error: 'Пользователь не аутентифицирован' });
      return
    }

    if (!categoryId || categoryId < 1 || categoryId > 8) {
      logger.warn(`Недопустимый ID категории: ${categoryId}`);
      res.status(400).json({ error: 'Недопустимая категория' });
      return
    }

    if (!checkPermission(req.user, categoryId, 'create')) {
      logger.warn(`Не разрешено для пользователя ${req.user.id} создавать статьи в категории ${categoryId}`);
      res.status(403).json({ error: 'В разрешении отказано' });
      return
    }

    const userId = req.user?.id; // ← ID текущего пользователя

    // 1. Найти автора, связанного с пользователем
    let author = await prisma.author.findFirst({
      where: { userId },
    });

    // 2. Если не найден — найти автора с order = 1
    if (!author) {
      author = await prisma.author.findFirst({
        where: { order: 1 },
      });
    }

    if (!author) {
      res.status(400).json({ error: 'Автор по умолчанию не найден' });
      return
    }

    // создаём статью и добавляем автора с ролью WRITER
    const article = await prisma.article.create({
      data: {
        title,
        excerpt,
        content,
        categoryId,
        cityId,
        coverImage,
        readTime,
        publishedAt: new Date(),
        authors: {
          create: [
            {
              author: { connect: { id: author.id } },
              role: AuthorRole.WRITER, // 👈 по умолчанию WRITER
            },
          ],
        },
      },
      include: {
        authors: {
          include: {
            author: {
              select: {
                id: true,
                displayName: true,
                email: true,
              },
            },
          },
        },
      },
    });

    logger.info(`Создана статья: ${article.id} пользователем ${req.user.id}`);
    res.status(201).json(article);
  } catch (error) {
    logger.error('Ошибка создания статьи:', error);
    res.status(500).json({ error: 'Серверная ошибка' });
  }
}

export async function updateArticle(req: AuthRequest, res: Response) : Promise<void> {
  try {
    const { title, excerpt, content, categoryId, cityId, coverImage, readTime, authors, gallery = [] } = req.body;

    if (!req.user) {
      res.status(401).json({ error: 'Пользователь не вошел в систему' });
      return
    }

    const existingArticle = await prisma.article.findUnique({
      where: { id: req.params.id },
      select: { id: true },
    });

    if (!existingArticle) {
      res.status(404).json({ error: 'Статья не найдена' });
      return;
    }

    if (!checkPermission(req.user, categoryId, 'edit')) {
      res.status(403).json({ error: 'В разрешении отказано' });
      return
    }

    const updateData: Prisma.ArticleUpdateInput = {
      title,
      excerpt,
      content,
      categoryId: Number(categoryId),
      cityId,
      coverImage,
      readTime
    };

    // Обновляем список авторов, если он передан
    if (Array.isArray(authors)) {
      updateData.authors = {
        // Удалим всех существующих авторов и добавим заново
        deleteMany: {},
        create: authors.map((a ) => ({
          author: { connect: { id: a.author?.id } },
          role: a.role as AuthorRole
        })),
      };
    }

    // Используется транзакция для атомарного обновления статьи и галереи
    const result = await prisma.$transaction(async (tx) => {
      const updatedArticle = await prisma.article.update({
        where: {id: req.params.id},
        data: updateData,
        include: {
          authors: {
            include: {
              author: {
                select: {
                  id: true,
                  displayName: true,
                  email: true,
                },
              },
            },
          },
        },
      });

      // Обработка обновления галереи
      if (gallery && Array.isArray(gallery)) {
        // Вначале удалить все существующие изображения из галереи статьи
        await prisma.galleryImage.deleteMany({
          where: {articleId: req.params.id}
        });

        // Создать новые изображения галереи
        if (gallery.length > 0) {
          await prisma.galleryImage.createMany({
            data: gallery.map((image: any, index: number) => ({
              articleId: req.params.id,
              url: image.url,
              caption: image.caption || '',
              alt: image.alt || '',
              width: image.width || 0,
              height: image.height || 0,
              size: image.size || 0,
              format: image.format || 'webp',
              order: index
            }))
          });
        }
      }

      res.json(updatedArticle);
    });
  } catch (error) {
    logger.error('Ошибка редактирования статьи:', error);
    res.status(500).json({ error: 'Серверная ошибка' });
  }
}

export async function activeArticle(req: AuthRequest, res: Response) : Promise<void> {
  try {
    const { isActive } = req.body;

    if (!req.user) {
      res.status(401).json({ error: 'Пользователь не вошел в систему' });
      return
    }

    const article = await prisma.article.findUnique({
      where: { id: req.params.id }
    });

    if (!article) {
      res.status(404).json({ error: 'Статья не найдена' });
      return
    }

    const updatedArticle = await prisma.article.update({
      where: { id: req.params.id },
      data: {
        isActive: isActive
      },
      include: {
        authors: {
          include: {
            author: {
              select: {
                id: true,
                displayName: true,
                email: true,
              },
            },
          },
        },
      }
    });

    res.json(updatedArticle);
  } catch (error) {
    logger.error('Ошибка активирования статьи:', error);
    res.status(500).json({ error: 'Серверная ошибка' });
  }
}

export async function reactArticle(req: AuthRequest, res: Response) : Promise<void> {
  try {
    const { reaction, likes, dislikes } = req.body;

    let newLikes:number = Number(likes);
    let newDisLikes:number = Number(dislikes);

    if (reaction === 'like') newLikes++;
    if (reaction === 'dislike') newDisLikes++;

    const updatedArticle = await prisma.article.update({
      where: { id: req.params.id },
      data: {
        likes: newLikes,
        dislikes: newDisLikes
      },
      include: {
        authors: {
          include: {
            author: {
              select: {
                id: true,
                displayName: true,
                email: true,
              },
            },
          },
        },
      }
    });

    res.json(updatedArticle);
  } catch (error) {
    logger.error('Ошибка установки реакции на статью:', error);
    res.status(500).json({ error: 'Серверная ошибка' });
  }
}

export async function deleteArticle(req: AuthRequest, res: Response) : Promise<void> {
  try {
    if (!req.user) {
      res.status(401).json({ error: 'Пользователь не вошел в систему' });
      return
    }

    const article = await prisma.article.findUnique({
      where: { id: req.params.id }
    });

    if (!article) {
      res.status(404).json({ error: 'Статья не найдена' });
      return
    }

    if (!checkPermission(req.user, article.categoryId.toString(), 'delete')) {
      res.status(403).json({ error: 'В разрешении отказано' });
      return
    }

    // Транзакция: удаляем зависимые данные перед удалением статьи - галерея и реакции
    await prisma.$transaction([
      prisma.galleryImage.deleteMany({
        where: { articleId: req.params.id },
      }),
      prisma.userReaction.deleteMany({
        where: { articleId: req.params.id },
      }),
      prisma.article.delete({
        where: { id: req.params.id },
      }),
    ]);

    res.json({ message: 'Статья успешно удалена' });
  } catch (error) {
    logger.error('Ошибка удаления статьи:', error);
    res.status(500).json({ error: 'Серверная ошибка' });
  }
}

export async function importArticles(req: AuthRequest, res: Response) : Promise<void> {
  const articles: Article[] = req.body;

  if (!req.user) {
    res.status(401).json({ error: 'Пользователь не вошел в систему' });
    return;
  }

  if (!Array.isArray(articles) || articles.length === 0) {
    res.status(400).json({ message: 'Ожидается непустой массив статей в теле запроса' });
    return;
  }

  let importedCount = 0;

  // Получение списка всех авторов для нахождения автора по имени
  const allAuthors = await prisma.author.findMany({
    select: { id: true, displayName: true },
  });

  const authorMap = new Map(allAuthors.map(a => [a.displayName, a.id]));

  try {
    for (const article of articles) {
      try {
        // Шаг 1: Создание статьи
        const authorsToConnect = [];

        // Добавление писателя
        const writerId = authorMap.get(article.authorName);
        if (writerId) {
          authorsToConnect.push({
            author: { connect: { id: writerId } },
            role: AuthorRole.WRITER,
          });
        }

        // Добавление соавтора
        const coWriterId = authorMap.get(article.coAuthorName);
        if (coWriterId) {
          authorsToConnect.push({
            author: { connect: { id: coWriterId } },
            role: AuthorRole.WRITER,
          });
        }

        // Добавление фотографа
        const photographerId = authorMap.get(article.photographerName);
        if (photographerId) {
          authorsToConnect.push({
            author: { connect: { id: photographerId } },
            role: AuthorRole.PHOTOGRAPHER,
          });
        }

        const newArticle = await prisma.article.create({
          data: {
            importId: article.importId,
            title: article.title,
            excerpt: article.excerpt,
            content: article.content,
            categoryId: article.categoryId,
            cityId: article.cityId,
            coverImage: DEFAULT_COVER_IMAGE,
            readTime: article.readTime,
            publishedAt: new Date(article.publishedAt),
            likes: article.likes || 0,
            dislikes: article.dislikes || 0,
            authors: {
              create: authorsToConnect,
            },
          },
        });

        // Шаг 2: Обработка coverImage
        if (article.coverImage) {
          const folder = `articles/${newArticle.id}`;
          const imageUrl = article.coverImage;

          try {
            // Извлечение изображение в виде буфера массива
            const imageResponse = await axios.get(imageUrl, { responseType: 'arraybuffer' });

            // Создание буфера из данных ответа
            const imageBuffer = Buffer.from(imageResponse.data, 'binary');

            // Получить тип контента и расширение
            const contentType = imageResponse.headers['content-type'];
            const fileExtension = path.extname(new URL(imageUrl).pathname) ||
                (contentType.includes('image/') ? `.${contentType.split('/')[1]}` : '');

            // Генерация имени файла
            const fileName = `cover-${Date.now()}${fileExtension}`;
            const webpFileName = path.basename(fileName, path.extname(fileName)) + '.webp';

            // Загрузка буфера в S3
            const uploadedUrl = await uploadBufferToS3(
                imageBuffer,
                folder,
                webpFileName,
                contentType,
                'medium',
                80
            );

            // Добавить обложку к статье
            await prisma.article.update({
              where: { id: newArticle.id },
              data: {
                coverImage: uploadedUrl
              },
            });
          } catch (imageError) {
            console.error(`Ошибка загрузки coverImage для статьи ${article.id}:`, imageError);
          }
        }

        // Шаг 3: Обработка массива images
        let updatedContent = newArticle.content;

        if (article.images && Array.isArray(article.images) && article.images.length > 0) {
          const folder = `articles/${newArticle.id}/images`;
          const uploadedImageUrls: string[] = [];

          // Загружаем каждое изображение в S3
          for (let i = 0; i < article.images.length; i++) {
            const imageUrl = article.images[i];
            try {
              const imageResponse = await axios.get(imageUrl, {responseType: 'arraybuffer'});
              const imageBuffer = Buffer.from(imageResponse.data, 'binary');
              const contentType = imageResponse.headers['content-type'];
              const fileExtension = path.extname(new URL(imageUrl).pathname) ||
                  (contentType.includes('image/') ? `.${contentType.split('/')[1]}` : '');
              const fileName = `image-${Date.now()}-${i}${fileExtension}`;
              const webpFileName = path.basename(fileName, path.extname(fileName)) + '.webp';

              const uploadedUrl = await uploadBufferToS3(
                  imageBuffer,
                  folder,
                  webpFileName,
                  contentType,
                  'medium',
                  80
              );
              uploadedImageUrls.push(uploadedUrl);
            } catch (imageError) {
              console.error(`Ошибка загрузки изображения ${imageUrl} для статьи ${newArticle.id}:`, imageError);
              uploadedImageUrls.push(''); // Добавляем пустую строку, чтобы сохранить порядок
            }
          }

          // Заменяем плейсхолдеры {{image1}}, {{image2}} и т.д. на uploadedUrl
          updatedContent = newArticle.content;
          const hasPlaceholders = uploadedImageUrls.some((_, index) => updatedContent.includes(`{{image${index + 1}}}`));
          if (!hasPlaceholders) {
            console.warn(`В content статьи ${newArticle.id} отсутствуют плейсхолдеры для изображений`);
          }

          uploadedImageUrls.forEach((uploadedUrl, index) => {
            if (uploadedUrl) {
              const placeholder = `{{image${index + 1}}}`;
              const imgTag = `<img src="${uploadedUrl}" alt="${article.imageSubs[index]}" data-scale="0.9" data-caption="${article.imageSubs[index]}" style="width: 90%">`;
              const regex = new RegExp(placeholder, 'g');
              updatedContent = updatedContent.replace(regex, imgTag);
            }
          });

          // Обновляем поле content в базе данных
          await prisma.article.update({
            where: {id: newArticle.id},
            data: {
              content: updatedContent,
            },
          });
        }

        importedCount++;
      } catch (articleError) {
        console.error(`Ошибка импорта статьи ${article.id}:`, articleError);
      }
    }

    res.status(200).json({
      message: `Импорт завершен. Успешно импортировано ${importedCount} из ${articles.length} статей.`,
    });
  } catch (err) {
    console.error('Ошибка обработки запроса:', err);
    res.status(500).json({ message: 'Ошибка сервера при импорте' });
  } finally {
    await prisma.$disconnect();
  }
}
