import { GraphQLError } from 'graphql';
import { UUID_REGEX } from '../../../../shared/constants.js';
import { ChargeTypeEnum } from '../../../../shared/enums.js';
import { errorSimplifier } from '../../../../shared/errors.js';
import { AdminContextProvider } from '../../../admin-context/providers/admin-context.provider.js';
import { ScopeProvider } from '../../../auth/providers/scope.provider.js';
import { suggestionDataSchema } from '../../../financial-entities/helpers/business-suggestion-data-schema.helper.js';
import { BusinessesProvider } from '../../../financial-entities/providers/businesses.provider.js';
import { ChargeTagsProvider } from '../../../tags/providers/charge-tags.provider.js';
import { TagsProvider } from '../../../tags/providers/tags.provider.js';
import { TransactionsProvider } from '../../../transactions/providers/transactions.provider.js';
import { getChargeType } from '../../helpers/charge-type.js';
import { calculateTotalAmount, getChargeBusinesses } from '../../helpers/common.helper.js';
import { ChargesProvider } from '../../providers/charges.provider.js';
import { missingConversionInfoSuggestions } from './conversion-suggeestions.resolver.js';
const missingInfoSuggestions = async (DbCharge, _, context, __) => {
    try {
        const { injector } = context;
        const { financialAccounts: { poalimBusinessId, etherScanBusinessId, krakenBusinessId, etanaBusinessId, }, defaultLocalCurrency, } = await injector.get(AdminContextProvider).getVerifiedAdminContext();
        const [chargeType, tags] = await Promise.all([
            getChargeType(DbCharge, injector),
            injector.get(ChargeTagsProvider).getTagsByChargeIDLoader.load(DbCharge.id),
        ]);
        // if all required fields are filled, no need for suggestions
        if (!!tags.length && !!DbCharge.user_description?.trim()) {
            return null;
        }
        if (chargeType === ChargeTypeEnum.Conversion) {
            return missingConversionInfoSuggestions(DbCharge, _, context, __);
        }
        const [formattedAmount, { allBusinessIds, mainBusinessId }] = await Promise.all([
            calculateTotalAmount(DbCharge.id, injector, defaultLocalCurrency),
            getChargeBusinesses(DbCharge.id, injector),
        ]);
        const chargeAmount = formattedAmount?.raw ?? 0;
        // if charge has a businesses, use it's suggestion data
        if (mainBusinessId) {
            const business = await injector
                .get(BusinessesProvider)
                .getBusinessByIdLoader.load(mainBusinessId);
            if (business?.suggestion_data) {
                const { data: suggestionData, error, success, } = suggestionDataSchema.safeParse(business.suggestion_data);
                if (!success) {
                    console.error('Failed to parse suggestion data for business', {
                        businessId: business.id,
                        error,
                    });
                    throw new GraphQLError('Failed to parse suggestion data for business');
                }
                return {
                    description: suggestionData.description,
                    tags: await Promise.all((suggestionData.tags ?? []).map(tag => UUID_REGEX.test(tag)
                        ? injector.get(TagsProvider).getTagByIDLoader.load(tag)
                        : injector.get(TagsProvider).getTagByNameLoader.load(tag))).then(tags => tags.filter(Boolean)),
                };
            }
        }
        if (allBusinessIds.length > 1) {
            const isKrakenIncluded = krakenBusinessId && allBusinessIds.includes(krakenBusinessId);
            const isEtherscanIncluded = etherScanBusinessId && allBusinessIds.includes(etherScanBusinessId);
            const isEtanaIncluded = etanaBusinessId && allBusinessIds.includes(etanaBusinessId);
            const isPoalimIncluded = poalimBusinessId && allBusinessIds.includes(poalimBusinessId);
            if (isKrakenIncluded && isEtherscanIncluded) {
                return {
                    description: 'Etherscan to Kraken transfer',
                    tags: await injector
                        .get(TagsProvider)
                        .getTagByNameLoader.load('financial')
                        .then(res => (res ? [res] : [])),
                };
            }
            if (isKrakenIncluded && isEtanaIncluded) {
                return {
                    description: 'Kraken to Etana transfer',
                    tags: await injector
                        .get(TagsProvider)
                        .getTagByNameLoader.load('financial')
                        .then(res => (res ? [res] : [])),
                };
            }
            if (isPoalimIncluded && isEtanaIncluded) {
                return {
                    description: 'Etana to Poalim transfer',
                    tags: await injector
                        .get(TagsProvider)
                        .getTagByNameLoader.load('financial')
                        .then(res => (res ? [res] : [])),
                };
            }
        }
        const allBusinesses = await injector.get(BusinessesProvider).getAllBusinesses();
        const suggestions = {};
        for (const business of allBusinesses) {
            if (!business.suggestion_data)
                continue;
            const { data: suggestionData, error, success, } = suggestionDataSchema.safeParse(business.suggestion_data);
            if (!success) {
                console.error('Failed to parse suggestion data for business', {
                    businessId: business.id,
                    error,
                });
                continue;
            }
            if (business.id in allBusinessIds) {
                return {
                    description: suggestionData.description,
                    tags: await Promise.all((suggestionData.tags ?? []).map(tag => UUID_REGEX.test(tag)
                        ? injector.get(TagsProvider).getTagByIDLoader.load(tag)
                        : injector.get(TagsProvider).getTagByNameLoader.load(tag))).then(tags => tags.filter(Boolean)),
                };
            }
            if (!suggestionData.phrases)
                continue;
            for (const phrase of suggestionData.phrases) {
                suggestions[phrase] = {
                    description: suggestionData.description,
                    tags: suggestionData.tags
                        ? await Promise.all(suggestionData.tags.map(tag => UUID_REGEX.test(tag)
                            ? injector.get(TagsProvider).getTagByIDLoader.load(tag)
                            : injector.get(TagsProvider).getTagByNameLoader.load(tag))).then(tags => tags.filter(Boolean))
                        : [],
                };
            }
        }
        const transactions = await injector
            .get(TransactionsProvider)
            .transactionsByChargeIDLoader.load(DbCharge.id);
        const description = transactions.map(t => t.source_description).join(' ');
        for (const [phrase, suggestion] of Object.entries(suggestions)) {
            if (Array.isArray(phrase) && new RegExp(phrase.join('|')).test(description)) {
                return suggestion;
            }
            if (description.includes(phrase)) {
                return suggestion;
            }
        }
        if (description.includes('ע\' העברת מט"ח') ||
            (description.includes('העברת מט"ח') && Math.abs(chargeAmount) < 400) ||
            (description.includes('מטח') && Math.abs(chargeAmount) < 400) ||
            description.includes('F.C.COM') ||
            description.includes('ע.מפעולות-ישיר') ||
            description.includes('ריבית חובה') ||
            description.includes('FEE')) {
            const sourceTransaction = transactions.length === 0
                ? 'Missing'
                : transactions.length === 1
                    ? transactions[0].source_reference
                    : `['${transactions.map(t => t.source_reference).join("','")}']`;
            return {
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('financial')
                    .then(res => (res ? [res] : [])),
                description: `Fees for source transaction=${sourceTransaction}`,
            };
        }
        if (description.includes('דותן שמחה') || description.includes('שמחה דותן')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', {
                month: '2-digit',
            });
            return {
                description: `${previousMonth}/2022 Salary`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('גולדשטין אורי')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', {
                month: '2-digit',
            });
            return {
                description: `${previousMonth}/2022 Salary`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('גרדוש')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', {
                month: '2-digit',
            });
            return {
                description: `${previousMonth}/2022 Salary`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('תובל')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', {
                month: '2-digit',
            });
            return {
                description: `${previousMonth}/2022 Salary`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('מנורה מבטחים פנס')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', {
                month: '2-digit',
            });
            return {
                description: `Pension ${previousMonth}/2022`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('פניקס אקסלנס')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', {
                month: '2-digit',
            });
            return {
                description: `Training Fund ${previousMonth}/2022`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('מיטב דש גמל ופנס')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', {
                month: '2-digit',
            });
            return {
                description: `Pension ${previousMonth}/2022`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('מגדל מקפת')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', {
                month: '2-digit',
            });
            return {
                description: `Pension ${previousMonth}/2022`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('מגדל השתלמות')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', {
                month: '2-digit',
            });
            return {
                description: `Training Fund ${previousMonth}/2022`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('ביטוח לאומי')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', {
                month: '2-digit',
            });
            return {
                description: `Social Security Deductions for Salaries ${previousMonth}/2022`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('LANCE GLOBAL')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', { month: 'long' });
            return {
                description: `The Guild Enterprise Support - ${previousMonth} 2022`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if ((description.includes('העברת מט"ח') &&
            (description.includes('fbv') || description.includes('fv'))) ||
            description.includes('kamil kisiela')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', {
                month: '2-digit',
            });
            return {
                description: `Software Development and Consulting ${previousMonth}/23`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('slava')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', { month: '2-digit' });
            return {
                description: `Web Development Services ${previousMonth}/23`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('COURIER PLUS INC')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', { month: 'long' });
            return {
                description: `GraphQL Hive Enterprise License - ${previousMonth} 2023`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('GOBRANDS')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', { month: 'long' });
            return {
                description: `GraphQL Hive Enterprise License - ${previousMonth} 2023`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('MEDIC FIRST AI')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', { month: 'long' });
            return {
                description: `GraphQL Hive Enterprise License - ${previousMonth} 2023`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('מס הכנסה')) {
            const flag = description.includes('מס הכנסה ני');
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', {
                month: '2-digit',
            });
            return {
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
                description: flag
                    ? `Tax for employees for ${previousMonth}/2022`
                    : `Advance Tax for ${previousMonth}/2022`,
            };
        }
        if (description.includes('המכס ומעמ-גביי תשלום') || description.includes('CUSTOM + V.A.T')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', {
                month: '2-digit',
            });
            return {
                description: `VAT for ${previousMonth}/2022`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('חניון')) {
            return {
                description: 'Parking',
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('transportation')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('deel')) {
            return {
                description: 'Laurin Salary',
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('GITHUB')) {
            const suggested = {
                description: 'GitHub Actions',
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
            if (chargeAmount <= -2000) {
                suggested.description = 'Monthly Sponsor for Benjie, Code-Hex, hayes';
            }
            else if (chargeAmount <= -1000) {
                suggested.description = 'Monthly Sponsor for Andarist, warrenday';
            }
            else {
                suggested.description = 'GitHub Actions';
            }
            return suggested;
        }
        if (chargeAmount === -4329) {
            return {
                description: 'Office rent',
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('APPLE COM BILL/ITUNES.COM')) {
            const flag = chargeAmount === -109.9;
            return {
                taxCategory: 'אתר',
                beneficiaaries: [], // NOTE: used to be ' '
                description: flag ? 'LinkedIn' : 'Apple Services',
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load(flag ? 'business' : 'computer')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('ע\' העברת מט"ח') ||
            (description.includes('העברת מט"ח') && Math.abs(chargeAmount) < 400) ||
            (description.includes('מטח') && Math.abs(chargeAmount) < 400) ||
            description.includes('F.C.COM') ||
            description.includes('ע.מפעולות-ישיר') ||
            description.includes('ריבית חובה') ||
            description.includes('FEE')) {
            const description = transactions.length
                ? `['${transactions.map(t => t.source_reference).join("','")}']`
                : 'Missing';
            //NOTE: multiple suggestions business
            return {
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('financial')
                    .then(res => (res ? [res] : [])),
                description,
            };
        }
        if (description.includes('ריבית זכות')) {
            //NOTE: multiple suggestions business
            return {
                description: 'Interest fees on Euro plus',
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('financial')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('פועלים- דמי כרטיס')) {
            //NOTE: multiple suggestions business
            return {
                description: 'Bank creditcard fees',
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('financial')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('אריה קריסטל')) {
            //NOTE: multiple suggestions business
            return {
                description: 'Water bill for 04-2022',
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('house')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('aleksandra')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', { month: '2-digit' });
            return {
                description: `Software Consulting Fees (${previousMonth}/2023)`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (description.includes('denelop')) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', { month: '2-digit' });
            return {
                description: `Software Development and Consulting ${previousMonth}/2023`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (chargeAmount === -12_000) {
            const current = new Date();
            current.setMonth(current.getMonth() - 1);
            const previousMonth = current.toLocaleString('default', { month: '2-digit' });
            return {
                description: `${previousMonth}/2022`,
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        if (chargeAmount === -600) {
            return {
                description: 'Matic Zavadlal - April 2021',
                tags: await injector
                    .get(TagsProvider)
                    .getTagByNameLoader.load('business')
                    .then(res => (res ? [res] : [])),
            };
        }
        return null;
    }
    catch (error) {
        throw errorSimplifier('Unexpected error fetching missing info suggestions', error);
    }
};
const commonChargeFields = {
    missingInfoSuggestions: missingInfoSuggestions,
};
export const chargeSuggestionsResolvers = {
    Query: {
        similarCharges: async (_, { chargeId, withMissingTags = false, withMissingDescription = false, descriptionDifferentThan, tagsDifferentThan, }, { injector }) => {
            if (!chargeId?.trim()) {
                throw new GraphQLError('Charge ID is required');
            }
            try {
                const [mainCharge, { allBusinessIds, mainBusinessId }] = await Promise.all([
                    injector
                        .get(ChargesProvider)
                        .getChargeByIdLoader.load(chargeId)
                        .catch(e => {
                        console.error('Error fetching charge', { chargeId, error: e });
                        throw new GraphQLError('Error fetching charge');
                    }),
                    getChargeBusinesses(chargeId, injector),
                ]);
                if (!mainCharge) {
                    throw new GraphQLError(`Charge not found: ${chargeId}`);
                }
                const similarCharges = await injector
                    .get(ChargesProvider)
                    .getSimilarCharges({
                    businessId: mainBusinessId,
                    businessArray: allBusinessIds,
                    withMissingTags,
                    withMissingDescription,
                    tagsDifferentThan: tagsDifferentThan ? [...tagsDifferentThan] : undefined,
                    descriptionDifferentThan,
                    ownerId: mainCharge.owner_id,
                })
                    .catch(e => {
                    console.error('Error fetching similar charges:', {
                        chargeId,
                        businessId: mainBusinessId,
                        businessArray: allBusinessIds,
                        error: e.message,
                    });
                    throw new GraphQLError('Error fetching similar charges');
                });
                return similarCharges;
            }
            catch (error) {
                throw errorSimplifier('Unexpected error fetching similar charges', error);
            }
        },
        similarChargesByBusiness: async (_, { businessId, ownerId: ownerIdInput, tagsDifferentThan, descriptionDifferentThan }, { injector }) => {
            if (!businessId?.trim()) {
                throw new GraphQLError('Business ID is required');
            }
            try {
                // Validate an explicit owner against the read scope (throws if out of
                // scope); otherwise default to the request's primary business.
                const trimmedOwnerId = ownerIdInput?.trim();
                let ownerId;
                if (trimmedOwnerId) {
                    await injector.get(ScopeProvider).getReadScope([trimmedOwnerId]);
                    ownerId = trimmedOwnerId;
                }
                else {
                    ownerId = (await injector.get(AdminContextProvider).getVerifiedAdminContext()).ownerId;
                }
                const similarCharges = await injector
                    .get(ChargesProvider)
                    .getSimilarCharges({
                    businessId,
                    tagsDifferentThan: tagsDifferentThan ? [...tagsDifferentThan] : undefined,
                    descriptionDifferentThan,
                    ownerId,
                })
                    .catch(e => {
                    console.error('Error fetching similar charges:', {
                        businessId,
                        ownerId,
                        error: e.message,
                    });
                    throw new GraphQLError('Error fetching similar charges by business');
                });
                return similarCharges;
            }
            catch (error) {
                throw errorSimplifier('Unexpected error fetching similar charges by business', error);
            }
        },
    },
    CommonCharge: commonChargeFields,
    FinancialCharge: commonChargeFields,
    ConversionCharge: commonChargeFields,
    SalaryCharge: commonChargeFields,
    InternalTransferCharge: commonChargeFields,
    DividendCharge: commonChargeFields,
    BusinessTripCharge: commonChargeFields,
    MonthlyVatCharge: commonChargeFields,
    BankDepositCharge: commonChargeFields,
    ForeignSecuritiesCharge: commonChargeFields,
    CreditcardBankCharge: commonChargeFields,
};
//# sourceMappingURL=charge-suggestions.resolver.js.map