import {
    ConfigPlugin, withInfoPlist,
    withAppDelegate,
    withEntitlementsPlist
} from "@expo/config-plugins";
import { promises as fs } from 'fs';
import path from 'path';
import fSystem from 'fs';
import { ExpoConfig } from "@expo/config-types";
import { SmartechBaseProps } from "./smartechBaseProps";
import { appdelegateSnippet, smartechBaseSnippet } from "./iosConstants";
import { Helper } from "./helper";


// Set custom entitlements plist
const modifyEntitlementsPlist: ConfigPlugin<SmartechBaseProps> = (config, props) => {
    return withEntitlementsPlist(config, async (newConfig) => {
        newConfig.modResults = {
            ...newConfig.modResults,
            "com.apple.security.application-groups": [`group.${props.ios.groupIdentifier}`],
        };
        return newConfig;
    });
};


// Set custom info plist
const modifyInfoPlist: ConfigPlugin<SmartechBaseProps> = (config, props) => {
    return withInfoPlist(config, (newConfig) => {
        newConfig.modResults = {
            ...newConfig.modResults,
            SmartechKeys: {
                SmartechAppGroup: `group.${props.ios.groupIdentifier}`,
                SmartechAppId: props.ios.appId,
                SmartechAutoFetchLocation: props.ios.autoFetchLocation,
                SmartechUseAdvId: props.ios.useAdvID,
            },
            ...(props.ios.smartechNudges.smartechNudgesEnabled && {
                HanselKeys: {
                    HanselAppId: props.ios.smartechNudges.appId,
                    HanselAppKey: props.ios.smartechNudges.appKey,
                }
            })
        };
        return newConfig;
    });
};

const addHanselURLScheme: ConfigPlugin<SmartechBaseProps> = (config, props) => {
    return withInfoPlist(config, (newConfig) => {
        
        const modResults = newConfig.modResults;
        const existingURLTypes = newConfig.modResults.CFBundleURLTypes || [];

        if (!props.ios.smartechNudges.smartechNudgesEnabled || !props.ios.smartechNudges.addTestDevice) {
            return newConfig;
        }

        if (props.ios.smartechNudges?.testDeviceURLName == undefined || props.ios.smartechNudges?.testDeviceURLSchema == undefined) {
            console.log(`Smartech Nudge Url scheme ${props.ios.smartechNudges?.testDeviceURLName} and ${props.ios.smartechNudges?.testDeviceURLSchema}`);
            return newConfig
        }

        const newEntry = {
            CFBundleTypeRole: "Editor",
            CFBundleURLName: props.ios.smartechNudges.testDeviceURLName,
            CFBundleURLSchemes: [props.ios.smartechNudges.testDeviceURLSchema || ""],
        };

        const isNewEntryAlreadyAdded = existingURLTypes.some((entry) => {
            return (
                entry.CFBundleURLName === newEntry.CFBundleURLName &&
                entry.CFBundleURLSchemes.includes(newEntry.CFBundleURLSchemes[0])
            );
        });

        if (!isNewEntryAlreadyAdded) {
            existingURLTypes.push(newEntry);
            modResults.CFBundleURLTypes = existingURLTypes;
        }
        return newConfig;
    });
}

const addSmartechHeaderMod: ConfigPlugin<SmartechBaseProps> = (config, props) => {
    return withAppDelegate(config, async (config) => {
        const { platformProjectRoot, projectName } = config.modRequest;

        if (projectName && platformProjectRoot) {

            try {
                const appDelegateHeaderPath = path.join(platformProjectRoot, projectName, appdelegateSnippet.fileName);
                const appDelegateHeaderContents = await fs.readFile(appDelegateHeaderPath, 'utf-8');
                // Add Smartech header snipper if not already present.
                if (!appDelegateHeaderContents.includes(appdelegateSnippet.smartechHeaderSnippet)) {
                    const modifiedAppDelegateHeaderContents = `${appDelegateHeaderContents}\n${appdelegateSnippet.smartechHeaderSnippet}`;
                    await fs.writeFile(appDelegateHeaderPath, modifiedAppDelegateHeaderContents, 'utf-8');
                } else {
                    console.log(`${appdelegateSnippet.smartechHeaderSnippet} is already added.`)
                }

            } catch (error) {
                console.error('Error modifying AppDelegate.h:', error);
            }
        }
        return config;
    });
};

const addSmartechHanseleHeaderMod: ConfigPlugin<SmartechBaseProps> = (config, props) => {
    return withAppDelegate(config, async (config) => {
        const { platformProjectRoot, projectName } = config.modRequest;

        if (platformProjectRoot && projectName) {
            try {
                const appDelegateHeaderPath = path.join(platformProjectRoot, projectName, appdelegateSnippet.fileName);
                const appDelegateHeaderContents = await fs.readFile(appDelegateHeaderPath, 'utf-8');
                // Add Hansel header snippet if Hansel is enabled and not already present
                if (props.ios.smartechNudges.smartechNudgesEnabled && !appDelegateHeaderContents.includes(appdelegateSnippet.hanselHeaderSnippet)) {
                    const modifiedAppDelegateHeaderContents = `${appDelegateHeaderContents}\n${appdelegateSnippet.hanselHeaderSnippet}`;
                    await fs.writeFile(appDelegateHeaderPath, modifiedAppDelegateHeaderContents, 'utf-8');
                } else {
                    console.log(`${appdelegateSnippet.hanselHeaderSnippet} is already added  or status of SmartechNudge: ${props.ios.smartechNudges.smartechNudgesEnabled}`);
                }
            } catch (error) {
                console.error('Error modifying AppDelegate.h:', error);
            }
        }
        return config;
    });
};

// Set custom AppDelegate contents modifications
const setCustomAppDelegateContentsMod: ConfigPlugin<SmartechBaseProps> = (config: ExpoConfig, props) => {
    return withAppDelegate(config, (cfg) => {
        const { modResults } = cfg;
        const { contents } = modResults;
        const appDelegatePath = cfg.modResults.path
        const smartechInitContent = addSmartechInitCode(contents, props);
        const updatedContent = Helper.Ios.addDeepLinkHandler(smartechInitContent, props);
        fSystem.writeFileSync(appDelegatePath, updatedContent, 'utf-8');
        modResults.contents = updatedContent;
        return cfg;
    });
};

// Helper function to modify AppDelegate contents
const addSmartechInitCode = (contents: string, props: SmartechBaseProps): string => {
    const lines = contents.split("\n");
    const didLaunchIndex = lines.findIndex(line => smartechBaseSnippet.regexPattern.test(line));

    if (didLaunchIndex === -1) {
        return contents;
    }

    // Prepare the lines to insert
    const sdkLines: string[] = [
        smartechBaseSnippet.smartechInit,
        ...(props.ios.isLogEnabled ? [smartechBaseSnippet.debugLevel] : []),
        smartechBaseSnippet.trackAppInstallUpdateBySmartech,
        ...((props.ios.smartechNudges.smartechNudgesEnabled && props.ios.smartechNudges.isLogEnabled )? [smartechBaseSnippet.hanselLogSnippet] : []),
    ];

    // Add the snippets before and after the `didFinishLaunching` index
    const resultLines = [
        ...lines.slice(0, didLaunchIndex + 2),
        ...sdkLines,
        ...lines.slice(didLaunchIndex + 2),
    ];

    return resultLines.join("\n");
};

// Set custom AppDelegate contents modifications
const modifyAppDelegateWithLinker: ConfigPlugin<SmartechBaseProps> = (config: ExpoConfig, props) => {

    if (!props.ios.smartechNudges.smartechNudgesEnabled || !props.ios.smartechNudges.addTestDevice) {
        return config;
    }

    return withAppDelegate(config, (config) => {
        const { modResults } = config;
        let { contents } = modResults;
        const codeBlock = `BOOL handleBySmartech = [[Smartech sharedInstance] application:application openURL:url options:options];
        if(!handleBySmartech) {
            return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];
        }
        return YES;`;
        const lines = contents.split("\n");
        if (contents.includes("openURL:")) {
            const modifiedContents = contents.replace(
                "return [super application:application openURL:url options:options] || [RCTLinkingManager application:application openURL:url options:options];",`${codeBlock}`);
            modResults.contents = modifiedContents;
        }
        return config;
    });
};

export const withNetcoreiOS: ConfigPlugin<SmartechBaseProps> = (config, props) => {
    config = modifyEntitlementsPlist(config, props);
    config = modifyInfoPlist(config, props);
    config = addHanselURLScheme(config, props);
    config = addSmartechHeaderMod(config, props);
    config = addSmartechHanseleHeaderMod(config, props);
    config = setCustomAppDelegateContentsMod(config, props);
    config = modifyAppDelegateWithLinker(config, props);
    return config;
}
