import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../../prisma/prisma.service';
import { UpdateProfileDto, AdminUpdateUserDto } from './dto/update-user.dto';

// ─── Helpers ──────────────────────────────────────────────────────────────────

/** MySQL JSON columns can store plain strings when inserted outside Prisma.
 *  This coerces any value into a proper JS array so the mobile app always
 *  gets `skills: string[]`, `hobbies: string[]`, `achievements: any[]`.
 */
function toArray(field: unknown): unknown[] {
  if (Array.isArray(field)) return field;
  if (typeof field === 'string') {
    const s = field.trim();
    if (!s) return [];
    // Maybe it's a JSON-encoded array: '["a","b"]'
    try {
      const parsed = JSON.parse(s);
      if (Array.isArray(parsed)) return parsed;
    } catch { /* not JSON */ }
    // Plain string — return as single item so the UI can at least show it
    return [s];
  }
  return [];
}

function normalizeUser<T extends Record<string, any>>(user: T | null): T | null {
  if (!user) return null;
  return {
    ...user,
    skills:       toArray(user.skills),
    achievements: toArray(user.achievements),
    hobbies:      toArray(user.hobbies),
  };
}

const PUBLIC_FIELDS = {
  id: true,
  name: true,
  profilePicture: true,
  bio: true,
  headline: true,
  profession: true,
  company: true,
  location: true,
  website: true,
  linkedin: true,
  skills: true,
  achievements: true,
  hobbies: true,
  role: true,
  status: true,
  createdAt: true,
  membership: { select: { type: true, validUntil: true } },
};

@Injectable()
export class UsersService {
  constructor(private prisma: PrismaService) {}

  async findAll(query: { search?: string; role?: string; page?: any; limit?: any }) {
    const search = query.search ?? '';
    const role = query.role;
    const page = parseInt(query.page ?? '1', 10) || 1;
    const limit = parseInt(query.limit ?? '20', 10) || 20;

    const where: any = { status: 'APPROVED' };
    if (search) where.OR = [{ name: { contains: search } }, { profession: { contains: search } }, { company: { contains: search } }];
    if (role) where.role = role;

    const [users, total] = await Promise.all([
      this.prisma.user.findMany({ where, select: PUBLIC_FIELDS, skip: (page - 1) * limit, take: limit, orderBy: { createdAt: 'desc' } }),
      this.prisma.user.count({ where }),
    ]);
    return { users: users.map(normalizeUser), total, page, limit };
  }

  async findOne(id: string) {
    const user = await this.prisma.user.findUnique({ where: { id }, select: PUBLIC_FIELDS });
    if (!user) throw new NotFoundException('User not found');
    return normalizeUser(user);
  }

  async findOneWithStats(id: string) {
    const [user, postCount, commentCount, reactionCount] = await Promise.all([
      this.prisma.user.findUnique({
        where: { id },
        select: {
          ...PUBLIC_FIELDS,
          email: true,
          phone: true,
          lastActiveAt: true,
          _count: { select: { feedPosts: true, feedComments: true, feedReactions: true, groupMemberships: true } },
        },
      }),
      this.prisma.feed.count({ where: { authorId: id } }),
      this.prisma.feedComment.count({ where: { userId: id } }),
      this.prisma.feedReaction.count({ where: { userId: id } }),
    ]);
    if (!user) throw new NotFoundException('User not found');
    return { ...normalizeUser(user), stats: { posts: postCount, comments: commentCount, reactions: reactionCount } };
  }

  async updateProfile(id: string, dto: UpdateProfileDto) {
    const user = await this.prisma.user.update({ where: { id }, data: dto as any, select: PUBLIC_FIELDS });
    return normalizeUser(user);
  }

  async updateProfilePicture(id: string, url: string) {
    return this.prisma.user.update({ where: { id }, data: { profilePicture: url }, select: PUBLIC_FIELDS });
  }

  async adminUpdate(id: string, dto: AdminUpdateUserDto) {
    const user = await this.prisma.user.findUnique({ where: { id } });
    if (!user) throw new NotFoundException('User not found');
    return this.prisma.user.update({ where: { id }, data: dto, select: PUBLIC_FIELDS });
  }

  async getPendingUsers() {
    const users = await this.prisma.user.findMany({
      where: { status: 'PENDING' },
      select: { ...PUBLIC_FIELDS, email: true, phone: true },
      orderBy: { createdAt: 'desc' },
    });
    return users.map(normalizeUser);
  }

  async softDelete(id: string) {
    return this.prisma.user.update({ where: { id }, data: { status: 'DELETED' } });
  }
}
