import { Controller, Get, Middleware, Post, Put } from '@overnightjs/core';
import { Request, Response } from 'express';
import { auth, AuthRequest } from '../middleware/auth';
import Plan from '../models/Plan';
import Subscription from '../models/Subscription';
import User from '../models/User';

@Controller('api/admin')
export class AdminController {

    /**
     * Get all registrations with their subscription/plan info
     * GET /api/admin/registrations
     * Admin only
     */
    @Get('registrations')
    @Middleware(auth)
    async getRegistrations(req: Request, res: Response) {
        try {
            const authReq = req as AuthRequest;
            if (authReq.user?.role !== 'admin') {
                res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
                return;
            }

            // Fetch both primary doctors and teammates
            const users = await User.find({ userType: { $in: ['doctor', 'dentist'] } })
                .select('firstName lastName email phone userType createdAt isActive clinic ownerId')
                .sort({ createdAt: -1 })
                .lean();

            const ownerIds = Array.from(new Set(
                users
                    .map((u: any) => u.ownerId?.toString())
                    .filter(Boolean)
            ));

            const owners = ownerIds.length
                ? await User.find({ _id: { $in: ownerIds } })
                    .select('firstName lastName email')
                    .lean()
                : [];

            const ownerMap = new Map<string, any>(
                owners.map((o: any) => [o._id.toString(), o])
            );

            // For teammates, subscription belongs to owner; for primary doctors, to self
            const subscriptionUserIds = Array.from(new Set(
                users.map((u: any) => (u.ownerId || u._id).toString())
            ));

            // Fetch their subscriptions with plan info
            const subscriptions = await Subscription.find({ userId: { $in: subscriptionUserIds } })
                .populate('planId', 'title price period')
                .sort({ createdAt: -1 })
                .lean();

            // Build a map: userId -> latest subscription
            const subMap: Record<string, any> = {};
            for (const sub of subscriptions) {
                const uid = sub.userId.toString();
                // Keep the most recent subscription per user (already sorted desc)
                if (!subMap[uid]) {
                    subMap[uid] = sub;
                }
            }

            const registrations = users.map((user) => {
                const subscriptionUserId = (user as any).ownerId || user._id;
                const sub = subMap[subscriptionUserId.toString()] || null;
                const plan = sub?.planId || null;
                const isFree = !sub || plan?.price === 0 || plan?.period === 'freely';
                const accountType = (user as any).ownerId ? 'Teammate' : 'Primary Doctor';
                const owner = (user as any).ownerId ? ownerMap.get((user as any).ownerId.toString()) : null;

                return {
                    _id: user._id,
                    firstName: user.firstName,
                    lastName: user.lastName,
                    email: user.email,
                    phone: user.phone || null,
                    userType: user.userType,
                    isActive: user.isActive,
                    ownerId: (user as any).ownerId || null,
                    accountType,
                    primaryDoctor: owner
                        ? {
                            _id: owner._id,
                            firstName: owner.firstName,
                            lastName: owner.lastName,
                            email: owner.email,
                        }
                        : null,
                    clinic: user.clinic || null,
                    registeredAt: user.createdAt,
                    subscription: sub
                        ? {
                            _id: sub._id,
                            status: sub.status,
                            startDate: sub.startDate,
                            endDate: sub.endDate,
                            category: sub.category,
                            autoRenew: sub.autoRenew,
                        }
                        : null,
                    plan: plan
                        ? {
                            _id: plan._id,
                            title: plan.title,
                            price: plan.price,
                            period: plan.period,
                        }
                        : null,
                    isFree,
                };
            });

            // Summary stats
            const totalRegistrations = registrations.length;
            const freeRegistrations = registrations.filter((r) => r.isFree).length;
            const paidRegistrations = totalRegistrations - freeRegistrations;

            // Plan distribution
            const planCounts: Record<string, number> = {};
            for (const reg of registrations) {
                const label = reg.plan ? reg.plan.title : 'No Plan';
                planCounts[label] = (planCounts[label] || 0) + 1;
            }

            res.status(200).json({
                success: true,
                data: {
                    registrations,
                    stats: {
                        total: totalRegistrations,
                        free: freeRegistrations,
                        paid: paidRegistrations,
                        byPlan: planCounts,
                    },
                },
            });
        } catch (error: any) {
            console.error('Error fetching admin registrations:', error);
            res.status(500).json({ success: false, error: error.message || 'Server error' });
        }
    }
    /**
     * Get all plans (for admin to assign to doctors)
     * GET /api/admin/plans
     * Admin only
     */
    @Get('plans')
    @Middleware(auth)
    async getPlans(req: Request, res: Response) {
        try {
            const authReq = req as AuthRequest;
            if (authReq.user?.role !== 'admin') {
                res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
                return;
            }

            const plans = await Plan.find().sort({ price: 1 }).lean();
            res.status(200).json({ success: true, data: plans });
        } catch (error: any) {
            res.status(500).json({ success: false, error: error.message || 'Server error' });
        }
    }

    /**
     * Seed the Free Forever plan if it doesn't exist
     * POST /api/admin/plans/seed-free-forever
     * Admin only
     */
    @Post('plans/seed-free-forever')
    @Middleware(auth)
    async seedFreeForever(req: Request, res: Response) {
        try {
            const authReq = req as AuthRequest;
            if (authReq.user?.role !== 'admin') {
                res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
                return;
            }

            let plan = await Plan.findOne({ period: 'freely', price: 0, title: 'Free Forever' });
            if (!plan) {
                plan = await Plan.create({
                    title: 'Free Forever',
                    price: 0,
                    period: 'freely',
                    features: ['Full access', 'Never expires', 'Admin granted'],
                });
            }

            res.status(200).json({ success: true, data: plan });
        } catch (error: any) {
            res.status(500).json({ success: false, error: error.message || 'Server error' });
        }
    }

    /**
     * Get a user's current subscription
     * GET /api/admin/subscription/:userId
     */
    @Get('subscription/:userId')
    @Middleware(auth)
    async getSubscriptionByUserId(req: Request, res: Response) {
        try {
            const authReq = req as AuthRequest;
            if (authReq.user?.role !== 'admin') {
                res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
                return;
            }
            const { userId } = req.params;
            const subscription = await Subscription.findOne({ userId })
                .sort({ updatedAt: -1, createdAt: -1 })
                .lean();

            if (!subscription) {
                res.status(200).json({ success: true, data: null });
                return;
            }

            const plan = subscription.planId ? await Plan.findById(subscription.planId).lean() : null;
            res.status(200).json({
                success: true,
                data: {
                    ...subscription,
                    planId: plan || subscription.planId,
                },
            });
        } catch (error: any) {
            res.status(500).json({ success: false, error: error.message || 'Server error' });
        }
    }

    /**
     * Update/assign a subscription plan to a user
     * PUT /api/admin/subscription/:userId
     */
    @Put('subscription/:userId')
    @Middleware(auth)
    async updateSubscriptionByUserId(req: Request, res: Response) {
        try {
            const authReq = req as AuthRequest;
            if (authReq.user?.role !== 'admin') {
                res.status(403).json({ success: false, error: 'Forbidden: Admins only' });
                return;
            }
            const { userId } = req.params;
            const { planId } = req.body;
            if (!planId) {
                res.status(400).json({ success: false, error: 'planId is required' });
                return;
            }
            const plan = await Plan.findById(planId);
            if (!plan) {
                res.status(404).json({ success: false, error: 'Plan not found' });
                return;
            }
            const isFreeForever = plan.price === 0 || plan.period === 'freely';
            const startDate = new Date();
            const endDate = isFreeForever
                ? new Date('2099-12-31T23:59:59.999Z')
                : new Date(new Date().setFullYear(new Date().getFullYear() + 1));

            let subscription = await Subscription.findOne({ userId }).sort({ updatedAt: -1, createdAt: -1 });
            if (subscription) {
                subscription.planId = plan._id as any;
                subscription.category = 'Medical';
                subscription.startDate = startDate;
                subscription.endDate = endDate;
                subscription.status = 'Active';
                subscription.autoRenew = false;
                subscription.maxDoctors = 1;
                await subscription.save();
            } else {
                subscription = await Subscription.create({
                    userId,
                    planId: plan._id,
                    category: 'Medical',
                    startDate,
                    endDate,
                    status: 'Active',
                    autoRenew: false,
                    maxDoctors: 1,
                });
            }

            await subscription.populate('planId');
            res.status(200).json({ success: true, data: subscription });
        } catch (error: any) {
            res.status(500).json({ success: false, error: error.message || 'Server error' });
        }
    }
}
