const {
  withAndroidManifest,
  withDangerousMod,
  withAppDelegate,
  withInfoPlist,
  withAppBuildGradle,
} = require('@expo/config-plugins');
const fs = require('fs');
const path = require('path');

const withJPush = (config, options = {}) => {
  const { appKey, channel = 'developer-default' } = options;

  if (!appKey) {
    throw new Error('JPush appKey is required in plugin options');
  }

  // 1. Android: Inject manifestPlaceholders into app/build.gradle
  config = withAppBuildGradle(config, (config) => {
    const block = '\n        manifestPlaceholders = [\n' +
      '            JPUSH_APPKEY: "' + appKey + '",\n' +
      '            JPUSH_CHANNEL: "' + channel + '"\n' +
      '        ]';

    const contents = config.modResults.contents;

    if (contents.includes('manifestPlaceholders')) {
      config.modResults.contents = contents.replace(
        /manifestPlaceholders\s*=\s*\[[\s\S]*?\]/,
        block.trim()
      );
    } else if (contents.includes('REACT_NATIVE_RELEASE_LEVEL')) {
      const lines = contents.split('\n');
      for (let i = 0; i < lines.length; i++) {
        if (lines[i].includes('REACT_NATIVE_RELEASE_LEVEL')) {
          lines.splice(i + 1, 0, block);
          break;
        }
      }
      config.modResults.contents = lines.join('\n');
    }

    return config;
  });

  // 2. Android: Add JPush metadata and permissions to AndroidManifest
  config = withAndroidManifest(config, (config) => {
    const manifest = config.modResults;

    if (!manifest.manifest['uses-permission']) {
      manifest.manifest['uses-permission'] = [];
    }

    const requiredPermissions = [
      'android.permission.RECEIVE_USER_PRESENT',
      'android.permission.POST_NOTIFICATIONS',
    ];

    requiredPermissions.forEach((permission) => {
      const exists = manifest.manifest['uses-permission'].find(
        (p) => p.$['android:name'] === permission
      );
      if (!exists) {
        manifest.manifest['uses-permission'].push({
          $: { 'android:name': permission },
        });
      }
    });

    return config;
  });

  // 3. iOS: Add JPush initialization to AppDelegate
  config = withAppDelegate(config, (config) => {
    const { contents } = config.modResults;

    if (!contents.includes('JPush')) {
      let newContents = contents;

      if (!newContents.includes('#import <UserNotifications/UserNotifications.h>')) {
        newContents = newContents.replace(
          /(#import "AppDelegate.h")/,
          `$1\n#import <UserNotifications/UserNotifications.h>`
        );
      }

      if (!newContents.includes('#import <jcore-react-native/JCoreModule.h>')) {
        newContents = newContents.replace(
          /(#import "AppDelegate.h")/,
          `$1\n#import <jcore-react-native/JCoreModule.h>`
        );
      }

      const didFinishLaunchPattern = /(- \(BOOL\)application:\(UIApplication \*\)application didFinishLaunchingWithOptions:\(NSDictionary \*\)launchOptions\s*\{)/;
      if (didFinishLaunchPattern.test(newContents)) {
        newContents = newContents.replace(
          didFinishLaunchPattern,
          `$1\n  // JPush initialization\n  [JCoreModule setupWithOption:launchOptions appKey:@"${appKey}" channel:@"${channel}" apsForProduction:NO];\n`
        );
      }

      const jpushMethods = `
// JPush: Register for remote notifications
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
  [JCoreModule registerDeviceToken:deviceToken];
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
  NSLog(@"did fail to register for remote notifications with error: %@", error);
}

// JPush: Handle remote notification
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
  [JCoreModule didReceiveRemoteNotification:userInfo];
  completionHandler(UIBackgroundFetchResultNewData);
}

// UNUserNotificationCenter delegate
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
  completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound);
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler {
  [JCoreModule didReceiveRemoteNotification:response.notification.request.content.userInfo];
  completionHandler();
}
`;

      if (!newContents.includes('JCoreModule registerDeviceToken')) {
        newContents = newContents.replace(
          /@end\s*$/,
          `${jpushMethods}\n@end\n`
        );
      }

      config.modResults.contents = newContents;
    }

    return config;
  });

  // 4. iOS: Add required capabilities and permissions to Info.plist
  config = withInfoPlist(config, (config) => {
    config.modResults.UIBackgroundModes = config.modResults.UIBackgroundModes || [];
    if (!config.modResults.UIBackgroundModes.includes('remote-notification')) {
      config.modResults.UIBackgroundModes.push('remote-notification');
    }

    return config;
  });

  return config;
};

module.exports = withJPush;