import { Injectable, HttpException, HttpStatus, Res, Inject } from "@nestjs/common"
import { InjectRepository } from "@nestjs/typeorm"
import { Repository, Like, Not, ILike } from "typeorm"
import { classToPlain } from "class-transformer"
import { responseMessages } from "../../messages/response-messages"
// Entities Files../../messages/comet-chat.ts
import { Constants } from "src/common/constants"
import { Campaign, CampaignStatus, ProfilePrivacy } from "../../entities/campaign.entity"
import { Users, UserRoles } from "../../entities/users.entity"
import slugify from "slugify"
import { AddInfluencerDto } from "./dtos/add-influencer.dto"
import { CampaignInfluencer, InfluencerStatus, JobStatus } from "src/entities/campaign_influencer.entity"
import { AddBookmarkDto } from "./dtos/add-bookmark.dto"
import { CampaignInfluencerBookmarks } from "src/entities/campaign_influencer_bookmark.entity"
import { UsersServices } from "src/common/services/users/users.service"
import { Draft, DraftStatus } from "src/entities/draft.entity"
import { DraftVersions, DraftVersionStatus } from "src/entities/draft_versions.entity"
import { DraftComments } from "src/entities/draft_comments.entity"
import { AddPostsDto } from "./dtos/add-posts.dto"
import { RejectCompletionRequest } from "src/entities/reject-completion-request.entity"
import { chatMessages } from "../../messages/comet-chat"
import { SocketGateway } from "src/common/services/socket/socket.gateway"
import { CampaignSaveDto } from "./dtos/save-campaign.dto"
import { InfluenceSaveCampaigns } from "src/entities/influencer-save-campaigns.entity"
import { DisputeRepository } from "./dispute.repository"
import { DispuetStatus, Dispute } from "src/entities/dispute.entity"
import { DisputeHistory } from "src/entities/dispute-history.entity"
import { CampaignRepository } from "../campaign/campaign.repository"
import { notificationMessages } from "src/messages/notifications-messages"
import { RedirectType } from "src/entities/notifications.entity"
import { CampaignService } from "../campaign/campaign.services"
const moment = require('moment');
// DTO Files

@Injectable()
export class DisputeService {
    constructor(
        private disputeRepository: DisputeRepository,
        private campaignRepository: CampaignRepository,
        private campaignService: CampaignService,
        private SocketGateway: SocketGateway,
        private UsersServices: UsersServices,

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

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

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

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

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

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

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

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

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


    ) { }



    async create(request: any, authUser: any) {

        let campaignInfluencer = await this.CampaignInfluencer.findOne({ relations: ['influencer'], where: { id: request.campaign_influencer_id } })

        if (!campaignInfluencer) {
            throw new HttpException(responseMessages.en.campaign.campaign_influencer_not_exists, HttpStatus.NOT_FOUND);
        }

        if (!campaignInfluencer.influencer) {
            throw new HttpException(responseMessages.en.campaign.campaign_influencer_not_exists, HttpStatus.NOT_FOUND);
        }

        let campaign = await this.Campaign.findOne({ relations: ['users'], where: { id: request.campaign_id } })
        if (!campaign) {
            throw new HttpException(responseMessages.en.campaign.campaign_not_exists, HttpStatus.NOT_FOUND);
        }
        if (!campaign.users) {
            throw new HttpException(responseMessages.en.campaign.campaign_brand_not_exists, HttpStatus.NOT_FOUND);
        }
        let whereConditions: any = { campaign_influencer: { id: campaignInfluencer.id } };
        if (authUser.role == 'brand') {
            whereConditions.is_brand_despute = true;
        }
        if (authUser.role == 'influencer') {
            whereConditions.is_influencer_despute = true;
        }

        const dispute = await this.Dispute.findOne({ where: whereConditions });
        if (dispute) {
            throw new HttpException(responseMessages.en.dispute.dispute_already_exists, HttpStatus.BAD_REQUEST);
        }


        await this.disputeRepository.create(request, campaignInfluencer, authUser, campaign);
        let sender = authUser;
        let receiver = {};
        let redirect_type = RedirectType.JOB_INPROGRESS;
        const metadata = { campaign_id: campaign.id, status: campaignInfluencer.status, brand_status: campaignInfluencer.status, influencer: { id: campaignInfluencer.influencer.id }, campaignName: campaign.campaign_name }

        let userName = authUser.display_name;
        if (authUser.role == 'influencer') {
            receiver = campaign.users;
            redirect_type = RedirectType.CAMPAIGN_MANAGEMENT;
        } else {
            receiver = campaignInfluencer.influencer;
            userName = campaign.users.company_name;
        }

        const notificationMessage = notificationMessages.en.descriptions.dispute.replace(':userName', userName).replace(":campaign_name", campaign.campaign_name);
        // this.campaignRepository.notification(receiver, notificationMessage, sender, redirect_type, campaign.id, campaign.slug, metadata);
        this.campaignService.sendCampaignNotification({
            type: 'dispute',
            receiver: receiver,
            description: notificationMessage,
            sender: sender,
            redirectType: redirect_type,
            redirectId: campaign.id,
            redirectSlug: campaign.slug,
            metadata: metadata,
            cometChat: {
                template: 'dispute',
                groupId: campaignInfluencer.id,
                userId: authUser.id
            }
        });
        this.campaignRepository.adminNotification(notificationMessage, sender, RedirectType.DISPUTE, campaign.id, campaign.slug)

        // this.campaignRepository.sendCometMessage(brandMessage, influencerMessage, adminMessage, campaignInfluencer.id, authUser.id)

        return;
    }


    async list(queryParam: any) {
        const reqPage = queryParam.page ? queryParam.page : 0
        const page = queryParam.page - 1
        const pageSize = queryParam.per_page ? queryParam.per_page : 10
        const offset = page * pageSize
        const nextPage = page + 1
        const nextOffset = nextPage * pageSize

        let sortByArr = {
            campaign_name: "campaign.campaign_name",
            created_at: "dispute.created_at",
            status: "dispute.status"
        }

        let sort_by = queryParam.sort_by || "created_at"
        let sort_type = queryParam.sort || "DESC"
        sort_by = sortByArr[sort_by]

        let queryBuilder = await this.disputeRepository.commonQuery();

        let query = queryBuilder.orderBy(sort_by, sort_type)

        if (queryParam.search) {
            query = query.andWhere(`(campaign.campaign_name ILIKE : search OR 
                                    CONCAT(brand.first_name, ' ', brand.last_name) ILIKE : search) OR 
                                    CONCAT(influencer.first_name, ' ', influencer.last_name) ILIKE : search`, { search: ` % ${queryParam.search} % ` })
        }

        if (reqPage !== 0) {
            query = query.skip(offset).take(pageSize)
        }

        const [results, total] = await query.getManyAndCount()

        return {
            data: results,
            total: total,
            hasMoreResults: total > nextOffset ? 1 : 0
        }
    }

    async details(param: any) {
        let queryBuilder = await this.disputeRepository.commonQuery();

        let response = await queryBuilder.leftJoin('dispute.disputeHistory', 'disputeHistory')
            .leftJoin('disputeHistory.dispute_by', 'dispute_by')
            .addSelect(["disputeHistory", "dispute_by.id", "dispute_by.slug", "dispute_by.first_name", "dispute_by.last_name", "dispute_by.email", "dispute_by.image", "dispute_by.country", "dispute_by.display_name", "dispute_by.role"])
            .where('dispute.slug = :slug', { slug: param.slug })
            .orderBy('disputeHistory.created_at', 'DESC')
            .getOne();

        if (!response) {
            throw new HttpException(responseMessages.en.dispute.dispute_not_found, HttpStatus.NOT_FOUND);
        }
        response['brandDetails'] = await this.campaignRepository.getCampaignBrandDetails(response.brand.id);
        return { data: response }
    }

    async solved(params: any, request: any, auth: any) {
        const dispute = await this.Dispute.findOne({ relations: ['campaign', 'campaign_influencer', 'brand', 'influencer'], where: { id: params.dispute_id } });
        if (!dispute) {
            throw new HttpException(responseMessages.en.dispute.dispute_not_found, HttpStatus.NOT_FOUND);
        }
        if (dispute.status == 'solved') {
            throw new HttpException(responseMessages.en.dispute.already_solved, HttpStatus.BAD_REQUEST);
        }

        let campaignInfluencer = dispute.campaign_influencer;
        campaignInfluencer.status = request.status;
        campaignInfluencer.influencer_status = request.status;
        campaignInfluencer.completed_date = request.status == 'closed' ? moment.utc().format("YYYY-MM-DD") : null;
        campaignInfluencer.job_status = request.status == 'closed' ? 'closed' : 'inprogress';
        let redirect_type = request.status == 'posting_deliverables' ? RedirectType.JOB_INPROGRESS : RedirectType.JOB_CLOSED;
        if (request.status == 'cancelled') {
            campaignInfluencer.job_status = JobStatus.CANCELLED;
            campaignInfluencer.status = InfluencerStatus.CLOSED;
            campaignInfluencer.influencer_status = InfluencerStatus.CLOSED;

            // REFUND AMOUNT IF JOB CANCELLEDd
            this.campaignRepository.refundAmount(campaignInfluencer.id);
        }

        if (request.status == 'closed') {
            const brand = dispute.brand;
            // MAKE PAYMENT IF INFLUENCER WIN & JOB CLOSED 
            this.campaignRepository.influencerPayment(campaignInfluencer.id, brand)
        }

        if (request.status == 'closed' || request.status == 'cancelled') {
            const chatCount = 1;
            await this.UsersServices.increasePermissionCount(dispute?.brand?.id, "work_order", chatCount);
        }
        await this.CampaignInfluencer.save(campaignInfluencer);

        dispute.status = DispuetStatus.SOLVED;
        dispute.winner = request.winner;
        dispute.message = request.message;
        await this.Dispute.save(dispute);

        const metadata = { campaign_id: dispute.campaign.id, status: campaignInfluencer.status, brand_status: campaignInfluencer.status, campaignName: dispute.campaign.campaign_name, influencer: { id: dispute.influencer.id } }
        const notificationMessage = notificationMessages.en.descriptions.dispute_resolved.replace(':status', request.status.replace('_', ' ')).replace(":campaign_name", dispute.campaign.campaign_name);;
        // SEND NOTIFICATION TO BRAND
        this.campaignService.sendCampaignNotification({
            type: 'dispute_resolved',
            receiver: dispute.brand,
            description: notificationMessage,
            sender: auth,
            redirectType: redirect_type,
            redirectId: dispute.campaign.id,
            redirectSlug: dispute.campaign.slug,
            metadata: metadata,
            cometChat: {
                groupId: campaignInfluencer.id,
                userId: auth.id
            }
        });
        // this.campaignRepository.notification(dispute.brand, notificationMessage, auth, RedirectType.CAMPAIGN_MANAGEMENT, dispute.campaign.id, dispute.campaign.slug, metadata);
        // SEND NOTIFICATION TO INFLUENCER
        // this.campaignRepository.notification(dispute.influencer, notificationMessage, auth, redirect_type, dispute.campaign.id, dispute.campaign.slug);
        this.campaignService.sendCampaignNotification({
            type: 'dispute_resolved',
            receiver: dispute.influencer,
            description: notificationMessage,
            sender: auth,
            redirectType: redirect_type,
            redirectId: dispute.campaign.id,
            redirectSlug: dispute.campaign.slug,
            metadata: metadata,
        });

        // await this.campaignRepository.sendCometMessage(brandMessage, influencerMessage, influencerMessage, campaignInfluencer.id, auth.id)
        // this.campaignRepository.sendCometMessage(request.message, request.message, campaignInfluencer.id, auth.id, 'text');

        this.campaignRepository.socketCampaignInfluencerDetails(campaignInfluencer.id);

        return;
    }
}
