import { groupBy } from 'lodash';
import React from 'react';
import { useIsYouTubeFingerprintRulesEnabled } from 'shared/features';
import { TimeRule } from 'src/components/fingerprintRulesOAPanel/deliveryRules/delivery-rules';
import Divider from 'src/components/fingerprintRulesOAPanel/deliveryRules/deliverySummary/divider/divider';
import Metadata from 'src/components/fingerprintRulesOAPanel/deliveryRules/deliverySummary/metadata/metadata';
import { PolicyType } from 'src/types';
import type { FC } from 'react';
import type { FingerprintRule } from 'src/types';

export const CLASS_NAME = 'DeliverySummary';

const TIKTOK_VALUE = 'TikTok';
const YOUTUBE_VALUE = 'YouTube';

interface CountersObject {
    tiktokYoutubeCounter: number;
    tiktokCounter: number;
    youtubeCounter: number;
}

interface Dictionary<T> {
    [index: string]: T;
}

export interface Props {
    isSubaccount?: boolean;
    vendorRules: FingerprintRule[];
    subaccountRules: FingerprintRule[];
    timeRuleFilter: TimeRule;
}

const groupRules = (rules: FingerprintRule[]) => {
    const tiktokRules = rules.filter(r => r.service === 'TikTok');
    return groupBy(tiktokRules, 'startDate');
};

const composeSummary = (
    group: Dictionary<FingerprintRule[]>,
    policy: string
) => {
    if (Object.keys(group).length === 0) return '';

    const conductor = [policy];
    Object.keys(group).forEach(startDate => {
        const rules = group[startDate];
        if (rules.length === 0) return;

        const groupByEndDate = groupBy(rules, 'endDate');

        Object.keys(groupByEndDate).forEach(endDate => {
            const rules = groupByEndDate[endDate];
            conductor.push(
                `${rules.length} ${
                    rules.length === 1 ? 'Country' : 'Countries'
                } for ${rules[0].service}`
            );
            if (startDate !== '-') conductor.push(`from ${startDate}`);
            if (endDate !== '-') conductor.push(`to ${endDate}`);
        });
    });

    return conductor.join(' ');
};

const renderSummary = (prefix: string, rules: FingerprintRule[]) => {
    const monetizedRules: FingerprintRule[] = [];
    const blockedRules: FingerprintRule[] = [];
    const carveoutRules: FingerprintRule[] = [];
    rules.forEach(r => {
        if (r.policy === PolicyType.monetize) monetizedRules.push(r);
        else if (r.policy === PolicyType.block_access) blockedRules.push(r);
        else carveoutRules.push(r);
    });

    const monetizedStartDate = groupRules(monetizedRules);

    const blockedStartDate = groupRules(blockedRules);

    const carveoutStartDate = groupRules(carveoutRules);

    const summary = [];

    const tms = composeSummary(monetizedStartDate, PolicyType.monetize);
    tms && summary.push(tms);

    const tbs = composeSummary(blockedStartDate, PolicyType.block_access);
    tbs && summary.push(tbs);

    const tcs = composeSummary(
        carveoutStartDate,
        PolicyType.carveout.replace('-', '')
    );
    tcs && summary.push(tcs);

    return summary.map(s => (
        <div key={s}>
            {prefix} &ndash; {s}
        </div>
    ));
};

const formatRulesByTime = (
    vendorRules: FingerprintRule[],
    subaccountRules: FingerprintRule[],
    filter: TimeRule
) => {
    let predicate: (rule: FingerprintRule) => boolean = (
        rule: FingerprintRule
    ) => {
        if (rule.policy === PolicyType['carveout']) return true;

        if (rule.startDate && new Date(rule.startDate) <= new Date()) {
            if (
                rule.endDate &&
                (rule.endDate === '-' || new Date(rule.endDate) > new Date())
            )
                return true;
        }

        return false;
    };

    if (filter === TimeRule.scheduled)
        predicate = (rule: FingerprintRule) =>
            !!rule.startDate && new Date(rule.startDate) > new Date();
    else if (filter === TimeRule.expired)
        predicate = (rule: FingerprintRule) =>
            !!rule.startDate && new Date(rule.startDate) > new Date();

    return {
        vendorRules: vendorRules.filter(predicate),
        subaccountRules: subaccountRules.filter(predicate),
    };
};

const generateMonetizeMessages = (counters: CountersObject) => {
    return generateMessages('Monetize', counters);
};

const generateBlockedMessages = (counters: CountersObject) => {
    return generateMessages('Block', counters);
};

const generateCarveoutMessages = (counters: CountersObject) => {
    return generateMessages('Carve-out', counters);
};

const generateMessages = (
    type: string,
    { tiktokYoutubeCounter, youtubeCounter, tiktokCounter }: CountersObject
) => {
    return (
        <>
            {!!tiktokYoutubeCounter && (
                <div>{`${type} ${tiktokYoutubeCounter} ${
                    tiktokYoutubeCounter === 1 ? 'Country' : 'Countries'
                } for TikTok, YouTube`}</div>
            )}
            {!!tiktokCounter && (
                <div>{`${type} ${tiktokCounter} ${
                    tiktokCounter === 1 ? 'Country' : 'Countries'
                } for TikTok`}</div>
            )}
            {!!youtubeCounter && (
                <div>{`${type} ${youtubeCounter} ${
                    youtubeCounter === 1 ? 'Country' : 'Countries'
                } for YouTube`}</div>
            )}
        </>
    );
};

const parseRulesByService = (rules: FingerprintRule[]) => {
    const monetizedCounters: CountersObject = {
        tiktokYoutubeCounter: 0,
        tiktokCounter: 0,
        youtubeCounter: 0,
    };
    const blockedCounters: CountersObject = {
        tiktokYoutubeCounter: 0,
        tiktokCounter: 0,
        youtubeCounter: 0,
    };
    const carveoutCounters: CountersObject = {
        tiktokYoutubeCounter: 0,
        tiktokCounter: 0,
        youtubeCounter: 0,
    };

    const monetizedRules: FingerprintRule[] = [];
    const blockedRules: FingerprintRule[] = [];
    const carveoutRules: FingerprintRule[] = [];
    rules
        .filter(r => r.service === TIKTOK_VALUE || r.service === YOUTUBE_VALUE)
        .forEach(r => {
            if (r.policy === PolicyType.monetize) monetizedRules.push(r);
            else if (r.policy === PolicyType.block_access) blockedRules.push(r);
            else carveoutRules.push(r);
        });

    const counterPredicate = (counters: CountersObject) => {
        return ([, rules]: [string, FingerprintRule[]]) => {
            if (
                rules.some(r => r.service === TIKTOK_VALUE) &&
                rules.some(r => r.service === YOUTUBE_VALUE)
            ) {
                counters.tiktokYoutubeCounter++;
            } else if (rules.some(r => r.service === TIKTOK_VALUE)) {
                counters.tiktokCounter++;
            } else {
                counters.youtubeCounter++;
            }
        };
    };

    Object.entries(groupBy(monetizedRules, 'territory')).forEach(
        counterPredicate(monetizedCounters)
    );

    Object.entries(groupBy(blockedRules, 'territory')).forEach(
        counterPredicate(blockedCounters)
    );

    Object.entries(groupBy(carveoutRules, 'territory')).forEach(
        counterPredicate(carveoutCounters)
    );

    return {
        monetizedCounters,
        blockedCounters,
        carveoutCounters,
    };
};

const renderNewSummary = (level: string, rules: FingerprintRule[]) => {
    const { monetizedCounters, blockedCounters, carveoutCounters } =
        parseRulesByService(rules);

    if (
        !monetizedCounters.tiktokYoutubeCounter &&
        !monetizedCounters.tiktokCounter &&
        !monetizedCounters.youtubeCounter &&
        !blockedCounters.tiktokYoutubeCounter &&
        !blockedCounters.tiktokCounter &&
        !blockedCounters.youtubeCounter &&
        !carveoutCounters.tiktokYoutubeCounter &&
        !carveoutCounters.tiktokCounter &&
        !carveoutCounters.youtubeCounter
    )
        return null;

    return (
        <Metadata label={level}>
            {generateMonetizeMessages(monetizedCounters)}
            {generateBlockedMessages(blockedCounters)}
            {generateCarveoutMessages(carveoutCounters)}
        </Metadata>
    );
};

const DeliverySummary: FC<Props> = ({
    isSubaccount = false,
    vendorRules,
    subaccountRules,
    timeRuleFilter,
}) => {
    const isYoutubeFingerprintRules = useIsYouTubeFingerprintRulesEnabled();

    const formatted = formatRulesByTime(
        vendorRules,
        subaccountRules,
        timeRuleFilter
    );

    if (isYoutubeFingerprintRules) {
        const vendorSummary = renderNewSummary('Account', vendorRules);
        const subaccountSummary = renderNewSummary(
            'Subaccount',
            subaccountRules
        );

        if (!vendorSummary && !subaccountSummary) return null;

        return (
            <div className={`${CLASS_NAME}-subsections`}>
                {vendorSummary || <Metadata label="Account">-</Metadata>}
                {isSubaccount && (
                    <>
                        <Divider />
                        {subaccountSummary || (
                            <Metadata label="Subaccount">-</Metadata>
                        )}
                    </>
                )}
            </div>
        );
    }

    const vendorSummary =
        vendorRules.length > 0 &&
        renderSummary('On Account', formatted.vendorRules);
    const subaccountSummary =
        subaccountRules.length > 0 &&
        renderSummary('On Subaccount', formatted.subaccountRules);

    return (
        <div className={CLASS_NAME}>
            {vendorSummary && <div>{vendorSummary}</div>}
            {subaccountSummary && <div>{subaccountSummary}</div>}
        </div>
    );
};

export default DeliverySummary;
