import { Injectable, HttpException, HttpStatus, Inject, forwardRef } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import axios from 'axios';
const moment = require('moment');
import { env, title } from 'process';
import { responseMessages } from 'src/messages/response-messages';
import { Brackets, Repository } from 'typeorm';
// Entities Files
import { Subscription, SubscriptionStatus } from 'src/entities/subscription.entity';
import { Users } from 'src/entities/users.entity';
import { Card } from 'src/entities/card.entity';
import { SubscriptionHistory } from 'src/entities/subscription-history.entity';
import { SocialMedias } from 'src/entities/social-medias.entity';
import { YoutubeServices } from '../youtube/youtube.service';
import { FacebookServices } from '../facebook/facebook.service';
import { InstagramServices } from '../instagram/instagram.service';
import { TiktokServices } from '../tiktok/tiktok.service';
import { StripeServices } from '../payment-gateway/stripe/stripe.service';
import { SocialMediaPosts } from 'src/entities/social-media-posts.entity';
import { UserPermissions } from 'src/entities/user-permissions.entity';
import { Campaign } from 'src/entities/campaign.entity';
import { CampaignService } from 'src/modules/campaign/campaign.services';
import { InfluencerCategory } from 'src/entities/influencer-caregories.entity';
import { BrandIndustries } from 'src/entities/brand-industries.entity';
import { PaymentService } from 'src/modules/payment/payment.service';

@Injectable()
export class UsersServices {

    constructor(
        private youtubeServices: YoutubeServices,
        private facebookServices: FacebookServices,
        private instagramServices: InstagramServices,
        private tiktokService: TiktokServices,
        private stripeService: StripeServices,
        private paymentService: PaymentService,

        @Inject(forwardRef(() => CampaignService))
        private campaignService: CampaignService,

        @InjectRepository(Users)
        private Users: Repository<Users>,

        @InjectRepository(Subscription)
        private Subscription: Repository<Subscription>,

        @InjectRepository(SocialMedias)
        private SocialMedias: Repository<SocialMedias>,

        @InjectRepository(Card)
        private Card: Repository<Card>,

        @InjectRepository(SocialMediaPosts)
        private SocialMediaPosts: Repository<SocialMediaPosts>,

        @InjectRepository(UserPermissions)
        private UserPermissions: Repository<UserPermissions>,

        @InjectRepository(Campaign)
        private Campaign: Repository<Campaign>,

        @InjectRepository(InfluencerCategory)
        private InfluencerCategory: Repository<InfluencerCategory>,

        @InjectRepository(BrandIndustries)
        private BrandIndustries: Repository<BrandIndustries>,

        @InjectRepository(SubscriptionHistory)
        private SubscriptionHistory: Repository<SubscriptionHistory>,
    ) { }

    /**
     * Get the list of users.
     * @param request The request object with access token.
     * @param sortBy The sortBy request as per sorting.
     * @param sortType The Sort Type request as per order of sort.
     * @param pageSize The list of given page size.
     * @param offset The list of given page number.
     * @returns A response whether the operation was successful.
     * @throws A HttpException if an error occurs.
     */
    async getUsersList(request: any, sortBy: string, sortType: any, pageSize: number, offset: number) {
        let query = await this.Users
            .createQueryBuilder('users')
            .where('(users.role = :role)', { role: request.role })
            .select([
                'users.id as id',
                'users.first_name as first_name',
                'users.last_name as last_name',
                'users.role as role',
                'users.email as email',
                'users.slug as slug',
                'users.image as image',
                'users.country_code as country_code',
                'users.phone_number as phone_number',
                'users.company_name as company_name',
                'users.is_active as is_active',
                'users.pending_steps as pending_steps',
                'users.business_type as business_type',
                'users.working_people as working_people',
                'users.total_followers as total_followers',
                'users.total_following as total_following',
                'users.engagement_ratio as engagement_ratio',
                'users.display_name as display_name',
                'users.remember_me as remember_me',
                'users.created_at as created_at',
            ])
            .groupBy('users.id')
            .orderBy(sortBy, sortType);
        if (request.role == 'influencer') {
            query = query.leftJoin('users.social_medias', 'social_medias');
        }
        if (request.search) {
            const search = request.search.normalize('NFKC');
            console.log('search', search);


            if (request.role == 'influencer') {
                query = query.andWhere(
                    `(
                    CONCAT(users.first_name, ' ', users.last_name) ILIKE :search OR
                    users.first_name ILIKE :search OR
                    users.display_name ILIKE :search OR
                    social_medias.social_user_name ILIKE :search OR
                    users.last_name ILIKE :search OR
                    users.company_name ILIKE :search OR
                    users.phone_number ILIKE :search OR
                    users.business_type ILIKE :search OR
                    users.email ILIKE :search
                )`,
                    { search: `%${search}%` });
            } else {
                query = query.andWhere(
                    `(
                    CONCAT(users.first_name, ' ', users.last_name) ILIKE :search OR
                    users.first_name ILIKE :search OR
                    users.display_name ILIKE :search OR
                    users.last_name ILIKE :search OR
                    users.company_name ILIKE :search OR
                    users.phone_number ILIKE :search OR
                    users.business_type ILIKE :search OR
                    users.email ILIKE :search
                )`,
                    { search: `%${search}%` });
            }
        }

        let total = (await query.getRawMany()).length;
        let results = await query.limit(pageSize).offset(offset).getRawMany();

        return {
            results: results,
            total: total,
        }
    }

    /**
     * Retrieves a user details based on role.
     */
    async getUserDetails(user, authUser: any) {
        const role = user.role;
        const lang = authUser?.language || 'en';
        const languageCode = authUser?.language || 'en';
        let userDetails = null;
        switch (role) {
            case 'brand':
                userDetails = await this.Users
                    .createQueryBuilder('users')
                    .leftJoinAndSelect('users.brandIndustries', 'brandIndustries')
                    .leftJoinAndSelect('brandIndustries.category', 'category', 'category.is_active = true')
                    .leftJoin("category.translations", "translation_req", "translation_req.language_code = :languageCode AND translation_req.deleted_at IS NULL", { languageCode })
                    .leftJoinAndSelect("category.translations", "translation",
                        "(translation.language_code = :languageCode OR (translation.language_code = 'en' AND translation_req.id IS NULL)) AND translation.deleted_at IS NULL",
                        { languageCode })
                    .leftJoinAndSelect('users.subscription', 'subscription', 'subscription.is_active = true')
                    .leftJoinAndSelect('subscription.plan', 'plan')
                    .leftJoinAndSelect('subscription.userPermissions', 'userPermissions')
                    .where('(users.id = :id)', { id: user.id })
                    .select(['users.id', 'users.first_name', 'users.last_name', 'users.email', 'users.role',
                        'users.language', 'users.is_verify_otp', 'users.country_code', 'users.is_offline_payment_allowed', 'users.offline_payment_allowed',
                        'users.phone_number', 'users.company_name', 'users.image', 'users.is_active',
                        'users.is_whatsapp_verified',
                        'users.pending_steps', 'users.business_type', 'users.working_people', 'users.gender', 'users.country',
                        'users.social_id', 'users.slug', 'users.is_subscribed', 'users.about_me', 'users.ai_summary', 'users.currency',
                        'brandIndustries.id', 'category.id', 'category.slug', 'category.title', 'translation.title', 'translation.description', 'translation.slug',
                        'subscription', 'plan', 'userPermissions'
                    ])
                    .getOne();

                userDetails['campaignCount'] = await this.Campaign.createQueryBuilder('camp')
                    .select(['COUNT(*) AS count', 'SUM(camp.total_budget) as total_budget'])
                    .where('camp.users = :user_id', { user_id: user.id })
                    .getRawMany();
                break;
            case 'admin':
                userDetails = user;
                break;
            case 'influencer':
                userDetails = await this.Users
                    .createQueryBuilder('users')
                    .leftJoinAndSelect('users.social_medias', 'social_medias')
                    .leftJoinAndSelect('users.influencerCategories', 'influencerCategories')
                    .leftJoinAndSelect('influencerCategories.category', 'category', 'category.is_active = true')
                    .leftJoin("category.translations", "translation_req", "translation_req.language_code = :languageCode AND translation_req.deleted_at IS NULL", { languageCode })
                    .leftJoinAndSelect("category.translations", "translation",
                        "(translation.language_code = :languageCode OR (translation.language_code = 'en' AND translation_req.id IS NULL)) AND translation.deleted_at IS NULL",
                        { languageCode })
                    .leftJoinAndSelect('social_medias.facebookPages', 'facebookPages')
                    .leftJoinAndSelect('social_medias.youtubeChannels', 'youtubeChannels')
                    .leftJoinAndSelect('social_medias.instagramProfiles', 'instagramProfiles')
                    .leftJoinAndSelect('social_medias.xiaohongshuProfiles', 'xiaohongshuProfiles')
                    .leftJoinAndSelect('social_medias.tikTokProfiles', 'tikTokProfiles')
                    .leftJoinAndSelect('users.userKeywords', 'userKeywords')
                    .leftJoinAndSelect('users.influencerPaymentMethods', 'influencerPaymentMethods')
                    .leftJoinAndSelect(
                        'userKeywords.keywords',
                        'keywords',
                        'keywords.deleted_at IS NULL'
                    )
                    .leftJoin('keywords.translations', 'keyword_translation_req_us', 'keyword_translation_req_us.language_code = :languageCode AND keyword_translation_req_us.deleted_at IS NULL', { languageCode })
                    .leftJoin('keywords.translations', 'keyword_translation_en_us', 'keyword_translation_en_us.language_code = \'en\' AND keyword_translation_en_us.deleted_at IS NULL')
                    .leftJoinAndSelect('keywords.translations', 'keyword_translation_us',
                        '(keyword_translation_us.language_code = :languageCode OR (keyword_translation_us.language_code = \'en\' AND keyword_translation_req_us.id IS NULL)) AND keyword_translation_us.deleted_at IS NULL',
                        { languageCode })
                    .where('(users.id = :id)', { id: user.id })
                    .select(['users.id', 'users.first_name', 'users.last_name', 'users.email', 'users.role',
                        'users.language', 'users.is_verify_otp', 'users.country_code', 'users.display_name',
                        'users.phone_number', 'users.company_name', 'users.image', 'users.is_active',
                        'users.pending_steps', 'users.business_type', 'users.working_people',
                        'users.social_id', 'users.slug', 'users.is_subscribed', 'users.currency',
                        'users.is_whatsapp_verified',
                        'users.social_type', 'social_medias.id', 'social_medias.social_type', 'social_medias.is_new_permission', 'social_medias.missing_permissions', 'social_medias.is_token_expire', 'social_medias.is_verified', 'social_medias.reel_average',
                        'users.total_followers', 'users.country', 'users.gender', 'users.about_me', 'users.ai_summary', 'users.total_following', 'users.engagement_ratio',
                        'facebookPages',
                        'youtubeChannels',
                        'instagramProfiles',
                        'xiaohongshuProfiles',
                        'tikTokProfiles',
                        'influencerCategories.id', 'category.id', 'category.slug', 'category.title', 'translation.title', 'translation.description', 'translation.slug',
                        'userKeywords', 'keywords', 'keyword_translation_us', 'influencerPaymentMethods'
                    ])
                    .withDeleted()
                    .getOne();


                userDetails['socialMediaPosts'] = await this.SocialMediaPosts.createQueryBuilder('socialMediaPosts')
                    .leftJoinAndSelect('socialMediaPosts.users', 'user') // Ensure user is joined
                    .where('user.id = :userId', { userId: user.id })
                    .orderBy('socialMediaPosts.like_count', 'DESC')
                    .limit(5)
                    .getMany() || [];
                break;
            default:
                throw new HttpException(responseMessages[lang].user.invalide_role, HttpStatus.NOT_FOUND);

        }

        const { created_at, updated_at, deleted_at, otp, otp_time, password, ...modifiedUser } = userDetails;

        return {
            ...modifiedUser,
        };

    }

    async getUserPermissions(userId: string) {
        return await this.UserPermissions.find({ where: { users: { id: userId } } });
    }

    async getUserPermission(userId: string, type: string) {
        return await this.UserPermissions.findOne({ relations: ['subscription', 'subscription.plan'], where: { users: { id: userId }, type: type } });
    }

    async increasePermissionCount(userId: string, type: string, increase = 1) {
        //await this.UserPermissions.update({ users: { id: userId }, type: type }, { remaining: () => "remaining + 1", used: () => "used - 1" });
        await this.UserPermissions.createQueryBuilder()
            .update()
            .set({
                remaining: () => `remaining + :increase`,
                used: () => `used - :increase`,
            })
            .where("type = :type", { type })
            .andWhere("usersId = :userId", { userId }) // adjust if column name is different
            .setParameters({ increase })
            .execute();
    }

    async decreasePermissionCount(userId: string, type: string) {

        const updateData: any = {
            remaining: () => "CASE WHEN remaining > 0 THEN remaining - 1 ELSE remaining END",
            used: () => "used + 1"
        };
        const whereCondition = { users: { id: userId }, type };

        if (type === 'browse_influencers_time_period' || type === 'export_influencer_time_limit_time_period') {
            const permission = await this.UserPermissions.findOne({ where: whereCondition });
            if (moment().isAfter(permission.expires_at) || permission.expires_at === null) {
                updateData.remaining = permission.limit - 1;
                updateData.used = 1;
                updateData.expires_at = moment().add(permission.time_period, 'hour').format('YYYY-MM-DD HH:mm:ss');
            }
        }

        // UPDATE USER PERMISSION
        await this.UserPermissions.update(whereCondition, updateData);
    }

    async checkPermission(userId: string, type: string) {
        // const userSubscription = await this.Subscription.findOne({ relations: ['plan'], where: { users: { id: userId }, status: 'active' } });
        // if (userSubscription.plan.plan_type == 'premium') {
        //     await this.decreasePermissionCount(userId, type);
        //     return true;
        // }
        const isAllowed = (await this.UserPermissions.findOne({ where: { users: { id: userId }, type: type } })).remaining ? true : false;
        if (isAllowed) {
            await this.decreasePermissionCount(userId, type);
        }
        return isAllowed;
    }

    async checkPermissionWithTimeLimit(userId: string, type: string) {
        // const userSubscription = await this.Subscription.findOne({ relations: ['plan'], where: { users: { id: userId }, status: 'active' } });
        // if (userSubscription.plan.plan_type == 'premium') {
        //     await this.decreasePermissionCount(userId, type);
        //     return true;
        // }
        try {
            const permission = await this.UserPermissions.findOne({
                where: { users: { id: userId }, type }
            });

            if (permission.expires_at === null || moment().isAfter(permission.expires_at)) {
                await this.decreasePermissionCount(userId, type);
                return true;
            }

            if (permission.remaining) {
                await this.decreasePermissionCount(userId, type);
                return true;
            }

            return false;
        } catch (error) {
            throw new HttpException(responseMessages.en.permission.permission_not_exists, HttpStatus.BAD_REQUEST);
        }

    }
    /**
     * Deletes a user based on their role.
     * Calls specific delete methods for 'brand' and 'influencer' roles.
     */

    async delete(user) {
        const role = user.role;
        const lang = user.language || 'en';
        let response = null;
        switch (role) {
            case 'brand':
                response = await this.deleteBrand(user);
                break;
            case 'influencer':
                response = await this.deleteInfluencer(user);
                break;
            default:
                throw new HttpException(responseMessages[lang].user.invalide_role, HttpStatus.NOT_FOUND);
        }
        console.log('response2', response);
        return response;
    }
    /**
     * Deletes a brand user and cancels their active subscription.
     */
    async deleteBrand(user) {

        const deleteStatus = await this.campaignService.beforeBrandDelete(user);
        console.log('deleteStatus', deleteStatus);

        if (deleteStatus) {
            const subscription = await this.Subscription.findOne({ where: { users: { id: user.id }, status: SubscriptionStatus.ACTIVE } });
            // CANCEL USER SUBSCRIPTION

            if (subscription) {
                await this.stripeService.cancelSubscription(subscription.stripe_subscription_id);
            }
            await this.BrandIndustries.softDelete({ users: { id: user.id } })
            await this.Card.softDelete({ users: { id: user.id } })
            await this.Subscription.softDelete({ users: { id: user.id } })
            await this.Users.softDelete({ id: user.id });
            await this.Campaign.softDelete({ users: { id: user.id } });
            return { status: true, message: responseMessages.en.user.brand_delete_success };
        }
        return { status: false, message: responseMessages.en.user.brand_delete_error };
    }

    /**
     * Deletes an influencer user and unlinks all of their social media accounts.
     */
    async deleteInfluencer(user) {
        const socialMedias = await this.SocialMedias.find({
            relations: ['users'],
            where: { users: { id: user.id } }
        });
        console.log('UNLINK SOCIAL MEDIA', socialMedias);
        for (const socialMedia of socialMedias) {
            switch (socialMedia.social_type) {
                case 'youtube':
                    await this.youtubeServices.unlinkYoutube(socialMedia);
                    break;
                case 'facebook':
                    await this.facebookServices.unlinkFacebook(socialMedia);
                    break;
                case 'instagram':
                    await this.instagramServices.unlinkInstagram(socialMedia);
                    break;
                case 'tiktok':
                    await this.tiktokService.unlinkTiktok(socialMedia);
                    break;
                default:
                    return false;
            }
        }
        await this.InfluencerCategory.softDelete({ users: { id: user.id } });
        await this.Users.softDelete({ id: user.id });
        return { status: true, message: responseMessages.en.user.influencer_delete_success };
    }

    async changeUserPermission() {
        const todayDate = moment().format('YYYY-MM-DD');
        const subscriptions = await this.Subscription.createQueryBuilder('subscription')
            .leftJoinAndSelect('subscription.plan', 'plan')
            .leftJoinAndSelect('plan.permission', 'permission')
            .leftJoinAndSelect('subscription.users', 'users')
            .where('subscription.status = :status', { status: SubscriptionStatus.UPCOMING })
            .andWhere('DATE(subscription.start_date) = :today', { today: todayDate })
            .orderBy('subscription.created_at', 'ASC')
            .getMany();

        for (const subscription of subscriptions) {
            let userPermissions = [];
            await this.UserPermissions.delete({ users: { id: subscription.users.id } });
            for (const permission of subscription.plan.permission) {
                userPermissions.push({
                    users: { id: subscription.users.id },
                    subscription: { id: subscription.id },
                    type: permission.time_period ? `${permission.type}_time_period` : permission.type,
                    limit: permission.limits,
                    used: 0,
                    remaining: permission.limits,
                    time_period: permission.time_period
                })
            }
            await this.Subscription.update({ id: subscription.id }, { is_active: true, status: SubscriptionStatus.ACTIVE });
            await this.SubscriptionHistory.update({ subsciption: { id: subscription.id } }, { status: SubscriptionStatus.ACTIVE });
        }
    }

    async convertToFreePlan() {
        const todayDate = moment().format('YYYY-MM-DD');
        const users = await this.Users.createQueryBuilder('users')
            .where("DATE(users.subscription_end_date + interval '1 day') = :today", { today: todayDate })
            .getMany();
        for (const user of users) {
            await this.Subscription.update({ users: { id: user.id } }, { is_active: false });
            const plan = await this.paymentService.getFreePlan();
            if (plan) {
                const body = { plan_id: plan.id, card_id: "", interval: "month" };
                // CREATE NEW SUBSCRIPTION
                await this.paymentService.subscription(body, user);
                user['is_subscribed'] = true;
                await this.Users.save(user);
            }
        }
    }
}
