
import prisma from '../../lib/prisma';
import { MaterialDTO, MaterialType } from '../../types';

export const MaterialService = {
  /**
   * Fetch all materials with relations (Author, Comments)
   */
  async getAllMaterials(filterType?: MaterialType, page = 1, limit = 20, search?: string) {
    const where: any = filterType ? { type: filterType } : {};
    if (search && search.trim()) {
      const q = search.trim();
      where.OR = [
        { title: { contains: q, mode: 'insensitive' } },
        { description: { contains: q, mode: 'insensitive' } },
        { tags: { some: { name: { contains: q, mode: 'insensitive' } } } }
      ];
    }

    const [materials, total] = await Promise.all([
      prisma.material.findMany({
        where,
        include: {
          author: {
            select: { id: true, username: true, avatarUrl: true, role: true, status: true, createdAt: true, lastLogin: true }
          },
          comments: {
            include: {
              author: { select: { id: true, username: true, role: true, status: true, createdAt: true, lastLogin: true, avatarUrl: true } }
            },
            orderBy: { createdAt: 'desc' }
          },
          favorites: true, // To count them
          tags: true
        },
        orderBy: { createdAt: 'desc' },
        skip: (page - 1) * limit,
        take: limit
      }),
      prisma.material.count({ where })
    ]);

    // Transform Prisma Result to DTO
    const items = materials.map(m => ({
      id: m.id,
      title: m.title,
      description: m.description,
      type: m.type as MaterialType,
      contentUrl: m.contentUrl || undefined,
      codeSnippet: m.codeSnippet || undefined,
      language: m.language || undefined,
      author: {
        ...m.author,
        role: m.author.role as any,
        createdAt: m.author.createdAt.toISOString(),
        lastLogin: m.author.lastLogin?.toISOString() || '',
        avatarUrl: m.author.avatarUrl || ''
      },
      stats: {
        views: m.views,
        downloads: m.downloads,
        favorites: m.favorites.length
      },
      tags: m.tags.map(t => t.name),
      createdAt: m.createdAt.toISOString(),
      comments: m.comments.map(c => ({
        id: c.id,
        content: c.content,
        createdAt: c.createdAt.toISOString(),
        author: {
          ...c.author,
          role: c.author.role as any,
          createdAt: c.author.createdAt.toISOString(),
          lastLogin: c.author.lastLogin?.toISOString() || '',
          avatarUrl: c.author.avatarUrl || ''
        }
      }))
    }));
    return { items, total };
  },

  async getMaterialsByAuthor(userId: string, page = 1, limit = 20) {
    const [materials, total] = await Promise.all([
      prisma.material.findMany({
      where: { authorId: userId },
      include: {
        author: {
          select: { id: true, username: true, avatarUrl: true, role: true, status: true, createdAt: true, lastLogin: true }
        },
        comments: {
          include: {
            author: { select: { id: true, username: true, role: true, status: true, createdAt: true, lastLogin: true, avatarUrl: true } }
          },
          orderBy: { createdAt: 'desc' }
        },
        favorites: true,
        tags: true
      },
      orderBy: { createdAt: 'desc' },
      skip: (page - 1) * limit,
      take: limit
    }),
    prisma.material.count({ where: { authorId: userId } })
    ]);

    const items = materials.map(m => ({
      id: m.id,
      title: m.title,
      description: m.description,
      type: m.type as MaterialType,
      contentUrl: m.contentUrl || undefined,
      codeSnippet: m.codeSnippet || undefined,
      language: m.language || undefined,
      author: {
        ...m.author,
        role: m.author.role as any,
        createdAt: m.author.createdAt.toISOString(),
        lastLogin: m.author.lastLogin?.toISOString() || '',
        avatarUrl: m.author.avatarUrl || ''
      },
      stats: {
        views: m.views,
        downloads: m.downloads,
        favorites: m.favorites.length
      },
      tags: m.tags.map(t => t.name),
      createdAt: m.createdAt.toISOString(),
      comments: m.comments.map(c => ({
        id: c.id,
        content: c.content,
        createdAt: c.createdAt.toISOString(),
        author: {
          ...c.author,
          role: c.author.role as any,
          createdAt: c.author.createdAt.toISOString(),
          lastLogin: c.author.lastLogin?.toISOString() || '',
          avatarUrl: c.author.avatarUrl || ''
        }
      }))
    }));
    return { items, total };
  },

  async getFavoritedMaterialsByUser(userId: string, page = 1, limit = 20) {
    const where = { favorites: { some: { userId } } };
    const [materials, total] = await Promise.all([
      prisma.material.findMany({
      where: { favorites: { some: { userId } } },
      include: {
        author: {
          select: { id: true, username: true, avatarUrl: true, role: true, status: true, createdAt: true, lastLogin: true }
        },
        comments: {
          include: {
            author: { select: { id: true, username: true, role: true, status: true, createdAt: true, lastLogin: true, avatarUrl: true } }
          },
          orderBy: { createdAt: 'desc' }
        },
        favorites: true,
        tags: true
      },
      orderBy: { createdAt: 'desc' },
      skip: (page - 1) * limit,
      take: limit
    }),
    prisma.material.count({ where })
    ]);

    const items = materials.map(m => ({
      id: m.id,
      title: m.title,
      description: m.description,
      type: m.type as MaterialType,
      contentUrl: m.contentUrl || undefined,
      codeSnippet: m.codeSnippet || undefined,
      language: m.language || undefined,
      author: {
        ...m.author,
        role: m.author.role as any,
        createdAt: m.author.createdAt.toISOString(),
        lastLogin: m.author.lastLogin?.toISOString() || '',
        avatarUrl: m.author.avatarUrl || ''
      },
      stats: {
        views: m.views,
        downloads: m.downloads,
        favorites: m.favorites.length
      },
      tags: m.tags.map(t => t.name),
      createdAt: m.createdAt.toISOString(),
      comments: m.comments.map(c => ({
        id: c.id,
        content: c.content,
        createdAt: c.createdAt.toISOString(),
        author: {
          ...c.author,
          role: c.author.role as any,
          createdAt: c.author.createdAt.toISOString(),
          lastLogin: c.author.lastLogin?.toISOString() || '',
          avatarUrl: c.author.avatarUrl || ''
        }
      }))
    }));
    return { items, total };
  },

  /**
   * Create a new Material
   */
  async createMaterial(userId: string, data: any) {
    return prisma.material.create({
      data: {
        title: data.title,
        description: data.description,
        type: data.type,
        codeSnippet: data.codeSnippet,
        contentUrl: data.contentUrl,
        language: data.language || 'text',
        authorId: userId,
        tags: {
          connectOrCreate: data.tags.map((tag: string) => ({
            where: { name: tag },
            create: { name: tag }
          }))
        }
      }
    });
  },

  async deleteMaterial(id: string) {
    return prisma.material.delete({ where: { id } });
  },

  async incrementView(id: string) {
    return prisma.material.update({
      where: { id },
      data: { views: { increment: 1 } }
    });
  },

  /**
   * Get material by ID with all relations
   */
  async getMaterialById(id: string): Promise<MaterialDTO | null> {
    const material = await prisma.material.findUnique({
      where: { id },
      include: {
        author: {
          select: { id: true, username: true, avatarUrl: true, role: true, status: true, createdAt: true, lastLogin: true }
        },
        comments: {
          include: {
            author: { select: { id: true, username: true, role: true, status: true, createdAt: true, lastLogin: true, avatarUrl: true } }
          },
          orderBy: { createdAt: 'desc' }
        },
        favorites: true,
        tags: true
      }
    });

    if (!material) return null;

    // Also increment view count
    await this.incrementView(id);

    // Transform to DTO
    return {
      id: material.id,
      title: material.title,
      description: material.description,
      type: material.type as MaterialType,
      contentUrl: material.contentUrl || undefined,
      codeSnippet: material.codeSnippet || undefined,
      language: material.language || undefined,
      author: {
        ...material.author,
        role: material.author.role as any,
        createdAt: material.author.createdAt.toISOString(),
        lastLogin: material.author.lastLogin?.toISOString() || '',
        avatarUrl: material.author.avatarUrl || ''
      },
      stats: {
        views: material.views + 1, // Include the increment we just did
        downloads: material.downloads,
        favorites: material.favorites.length
      },
      tags: material.tags.map(t => t.name),
      createdAt: material.createdAt.toISOString(),
      comments: material.comments.map(c => ({
        id: c.id,
        content: c.content,
        createdAt: c.createdAt.toISOString(),
        author: {
          ...c.author,
          role: c.author.role as any,
          createdAt: c.author.createdAt.toISOString(),
          lastLogin: c.author.lastLogin?.toISOString() || '',
          avatarUrl: c.author.avatarUrl || ''
        }
      }))
    };
  },

  /**
   * Add a comment to a material
   */
  async addComment(materialId: string, userId: string, content: string) {
    return prisma.comment.create({
      data: {
        content,
        authorId: userId,
        materialId
      },
      include: {
        author: { select: { id: true, username: true, avatarUrl: true, role: true, status: true, createdAt: true, lastLogin: true } }
      }
    });
  },

  /**
   * Toggle favorite status for a material
   * Returns the new favorite count
   */
  async toggleFavorite(materialId: string, userId: string): Promise<number> {
    // Check if already favorited
    const existing = await prisma.favorite.findUnique({
      where: {
        userId_materialId: {
          userId,
          materialId
        }
      }
    });

    if (existing) {
      // Remove favorite
      await prisma.favorite.delete({
        where: {
          userId_materialId: {
            userId,
            materialId
          }
        }
      });
    } else {
      // Add favorite
      await prisma.favorite.create({
        data: {
          userId,
          materialId
        }
      });
    }

    // Return new favorite count
    const count = await prisma.favorite.count({
      where: { materialId }
    });

    return count;
  },

  /**
   * Increment download count
   */
  async incrementDownload(id: string) {
    return prisma.material.update({
      where: { id },
      data: { downloads: { increment: 1 } }
    });
  }
};
