const express = require('express');
const { APP_PORTS } = require('../../src/utilities/constants');

/**
 * Arr smart-connect routes factory
 * @param {Object} deps - Explicit dependencies
 * @param {Object} deps.credentialManager - Credential manager
 * @param {Function} deps.fetchT - Timeout-wrapped fetch
 * @param {Function} deps.asyncHandler - Async route handler wrapper
 * @param {Function} deps.errorResponse - Error response helper
 * @param {Object} deps.log - Logger instance
 * @param {Object} deps.helpers - Arr helpers module
 * @param {Object} deps.servicesStateManager - Services state manager
 * @param {Object} deps.notification - Notification helper
 * @returns {express.Router}
 */
module.exports = function({ credentialManager, servicesStateManager, fetchT, asyncHandler, errorResponse: _errorResponse, log: _log, helpers, notification }) {
  const router = express.Router();

  const ctx = {
    servicesStateManager,
    notification
  };

  // Smart Connect: Unified orchestration endpoint
  router.post('/arr/smart-connect', asyncHandler(async (req, res) => {
    const { services: inputServices, configurePlex, configureProwlarr, configureSeerr, saveCredentials } = req.body;
    const steps = [];
    const connectedServices = {}; // { radarr: { url, apiKey }, sonarr: { url, apiKey }, ... }

    // Phase 1: Test all provided services and resolve credentials
    const arrServices = ['radarr', 'sonarr', 'prowlarr'];
    for (const svc of arrServices) {
      const input = inputServices?.[svc];
      let apiKey = input?.apiKey;
      let url = input?.url;

      // Fallback to stored credentials
      if (!apiKey) {
        const credKey = `arr.${svc}.apikey`;
        apiKey = await credentialManager.retrieve(credKey);
        if (!url) {
          const metadata = await credentialManager.getMetadata(credKey);
          url = metadata?.url;
        }
      }

      // Fallback URL from services.json
      if (!url && apiKey) {
        try {
          const data = await ctx.servicesStateManager.read();
          const svcList = Array.isArray(data) ? data : data.services || [];
          const found = svcList.find(s => s.id === svc && s.isExternal);
          if (found?.externalUrl) url = found.externalUrl;
        } catch (e) { /* ignore */ }
      }

      if (!apiKey || !url) continue;

      // Test connection
      const test = await helpers.testServiceConnection(svc, url, apiKey);
      steps.push({
        step: `Test ${svc.charAt(0).toUpperCase() + svc.slice(1)} connection`,
        status: test.success ? 'success' : 'failed',
        details: test.success ? `v${test.version}` : test.error
      });

      if (test.success) {
        connectedServices[svc] = { url, apiKey };

        // Save credentials
        if (saveCredentials) {
          const stored = await credentialManager.store(`arr.${svc}.apikey`, apiKey, {
            service: svc, source: 'external', url,
            lastVerified: new Date().toISOString(),
            version: test.version
          });
          steps.push({
            step: `Save ${svc} credentials`,
            status: stored ? 'success' : 'failed',
            details: stored ? 'Encrypted and saved' : 'Storage failed'
          });
        }
      }
    }

    // Phase 2: Handle Plex
    let plexToken = null;
    let plexUrl = null;
    if (configurePlex) {
      plexToken = await helpers.getPlexToken('plex');
      if (!plexToken) plexToken = await credentialManager.retrieve('arr.plex.token');

      if (plexToken) {
        // Get Plex URL
        plexUrl = `http://host.docker.internal:${APP_PORTS.plex}`;
        try {
          const data = await ctx.servicesStateManager.read();
          const svcList = Array.isArray(data) ? data : data.services || [];
          const plexSvc = svcList.find(s => s.id === 'plex' || s.appTemplate === 'plex');
          if (plexSvc?.url) plexUrl = plexSvc.url;
        } catch (e) { /* use default */ }
      }
    }

    // Phase 3: Configure Overseerr (uses Plex-based session auth)
    if (configureSeerr && (connectedServices.radarr || connectedServices.sonarr || (configurePlex && plexToken))) {
      const overseerrSession = await helpers.getOverseerrSession();
      const overseerrUrl = `http://host.docker.internal:${APP_PORTS.seerr}`;

      if (!overseerrSession) {
        steps.push({
          step: 'Get Overseerr API key',
          status: 'failed',
          details: 'Could not authenticate with Overseerr (Plex not running or not linked)'
        });
      } else {
        steps.push({ step: 'Get Overseerr API key', status: 'success', details: 'Extracted from container' });
        const overseerrCookie = overseerrSession.cookie;

        // Configure Radarr in Overseerr
        if (connectedServices.radarr) {
          try {
            const radarrUrl = connectedServices.radarr.url.replace(/\/+$/, '');
            const radarrUrlObj = new URL(radarrUrl);
            const radarrBasePath = radarrUrlObj.pathname.replace(/\/+$/, '');

            // Fetch quality profiles
            const profilesRes = await fetchT(`${radarrUrl}/api/v3/qualityprofile`, {
              headers: { 'X-Api-Key': connectedServices.radarr.apiKey },
              signal: AbortSignal.timeout(10000)
            });
            const profiles = profilesRes.ok ? await profilesRes.json() : [];

            // Use stored quality profile preference, fallback to first profile
            const radarrMeta = await credentialManager.getMetadata('arr.radarr.apikey');
            let defaultProfile = profiles[0] || { id: 1, name: 'Any' };
            if (radarrMeta?.qualityProfileId) {
              const stored = profiles.find(p => p.id === radarrMeta.qualityProfileId);
              if (stored) defaultProfile = stored;
            }

            // Fetch root folders
            const rootFoldersRes = await fetchT(`${radarrUrl}/api/v3/rootfolder`, {
              headers: { 'X-Api-Key': connectedServices.radarr.apiKey },
              signal: AbortSignal.timeout(10000)
            });
            const rootFolders = rootFoldersRes.ok ? await rootFoldersRes.json() : [];
            const defaultRootFolder = rootFolders[0]?.path || '/movies';

            // Seerr runs in Docker — localhost/127.0.0.1 won't reach sibling containers
            const radarrHost = ['localhost', '127.0.0.1'].includes(radarrUrlObj.hostname)
              ? 'host.docker.internal' : radarrUrlObj.hostname;

            const radarrConfig = {
              name: 'Radarr',
              hostname: radarrHost,
              port: parseInt(radarrUrlObj.port) || (radarrUrlObj.protocol === 'https:' ? 443 : APP_PORTS.radarr),
              apiKey: connectedServices.radarr.apiKey,
              useSsl: radarrUrlObj.protocol === 'https:',
              baseUrl: radarrBasePath || '',
              activeProfileId: defaultProfile.id,
              activeProfileName: defaultProfile.name,
              activeDirectory: defaultRootFolder,
              is4k: false,
              minimumAvailability: 'released',
              isDefault: true,
              externalUrl: connectedServices.radarr.url,
              tags: []
            };

            const radarrRes = await fetchT(`${overseerrUrl}/api/v1/settings/radarr`, {
              method: 'POST',
              headers: { 'Content-Type': 'application/json', 'Cookie': overseerrCookie },
              body: JSON.stringify(radarrConfig),
              signal: AbortSignal.timeout(10000)
            });

            steps.push({
              step: 'Configure Radarr in Overseerr',
              status: radarrRes.ok ? 'success' : 'failed',
              details: radarrRes.ok ? `Profile: ${defaultProfile.name}, Root: ${defaultRootFolder}` : await radarrRes.text()
            });
          } catch (e) {
            steps.push({ step: 'Configure Radarr in Overseerr', status: 'failed', details: e.message });
          }
        }

        // Configure Sonarr in Overseerr
        if (connectedServices.sonarr) {
          try {
            const sonarrUrl = connectedServices.sonarr.url.replace(/\/+$/, '');
            const sonarrUrlObj = new URL(sonarrUrl);
            const sonarrBasePath = sonarrUrlObj.pathname.replace(/\/+$/, '');

            const profilesRes = await fetchT(`${sonarrUrl}/api/v3/qualityprofile`, {
              headers: { 'X-Api-Key': connectedServices.sonarr.apiKey },
              signal: AbortSignal.timeout(10000)
            });
            const profiles = profilesRes.ok ? await profilesRes.json() : [];

            // Use stored quality profile preference, fallback to first profile
            const sonarrMeta = await credentialManager.getMetadata('arr.sonarr.apikey');
            let defaultProfile = profiles[0] || { id: 1, name: 'Any' };
            if (sonarrMeta?.qualityProfileId) {
              const stored = profiles.find(p => p.id === sonarrMeta.qualityProfileId);
              if (stored) defaultProfile = stored;
            }

            const rootFoldersRes = await fetchT(`${sonarrUrl}/api/v3/rootfolder`, {
              headers: { 'X-Api-Key': connectedServices.sonarr.apiKey },
              signal: AbortSignal.timeout(10000)
            });
            const rootFolders = rootFoldersRes.ok ? await rootFoldersRes.json() : [];
            const defaultRootFolder = rootFolders[0]?.path || '/tv';

            let languageProfileId = 1;
            try {
              const langRes = await fetchT(`${sonarrUrl}/api/v3/languageprofile`, {
                headers: { 'X-Api-Key': connectedServices.sonarr.apiKey },
                signal: AbortSignal.timeout(5000)
              });
              if (langRes.ok) {
                const langProfiles = await langRes.json();
                languageProfileId = langProfiles[0]?.id || 1;
              }
            } catch (e) { /* Sonarr v4 doesn't need this */ }

            const sonarrHost = ['localhost', '127.0.0.1'].includes(sonarrUrlObj.hostname)
              ? 'host.docker.internal' : sonarrUrlObj.hostname;

            const sonarrConfig = {
              name: 'Sonarr',
              hostname: sonarrHost,
              port: parseInt(sonarrUrlObj.port) || (sonarrUrlObj.protocol === 'https:' ? 443 : APP_PORTS.sonarr),
              apiKey: connectedServices.sonarr.apiKey,
              useSsl: sonarrUrlObj.protocol === 'https:',
              baseUrl: sonarrBasePath || '',
              activeProfileId: defaultProfile.id,
              activeProfileName: defaultProfile.name,
              activeDirectory: defaultRootFolder,
              activeLanguageProfileId: languageProfileId,
              is4k: false,
              isDefault: true,
              enableSeasonFolders: true,
              externalUrl: connectedServices.sonarr.url,
              tags: []
            };

            const sonarrRes = await fetchT(`${overseerrUrl}/api/v1/settings/sonarr`, {
              method: 'POST',
              headers: { 'Content-Type': 'application/json', 'Cookie': overseerrCookie },
              body: JSON.stringify(sonarrConfig),
              signal: AbortSignal.timeout(10000)
            });

            steps.push({
              step: 'Configure Sonarr in Overseerr',
              status: sonarrRes.ok ? 'success' : 'failed',
              details: sonarrRes.ok ? `Profile: ${defaultProfile.name}, Root: ${defaultRootFolder}` : await sonarrRes.text()
            });
          } catch (e) {
            steps.push({ step: 'Configure Sonarr in Overseerr', status: 'failed', details: e.message });
          }
        }

        // Connect Plex to Overseerr
        if (configurePlex && plexToken) {
          try {
            const plexResult = await helpers.connectPlexToOverseerr(plexUrl, plexToken, overseerrUrl, overseerrCookie);
            steps.push({
              step: 'Connect Plex to Overseerr',
              status: 'success',
              details: `${plexResult.serverName} - ${plexResult.libraries.length} libraries synced`
            });
          } catch (e) {
            steps.push({ step: 'Connect Plex to Overseerr', status: 'failed', details: e.message });
          }
        }
      }
    }

    // Phase 4: Configure Prowlarr
    if (configureProwlarr && connectedServices.prowlarr) {
      const appsToConnect = {};
      if (connectedServices.radarr) appsToConnect.radarr = connectedServices.radarr;
      if (connectedServices.sonarr) appsToConnect.sonarr = connectedServices.sonarr;

      if (Object.keys(appsToConnect).length > 0) {
        try {
          const prowlarrResults = await helpers.configureProwlarrApps(
            connectedServices.prowlarr.url.replace(/\/+$/, ''),
            connectedServices.prowlarr.apiKey,
            appsToConnect
          );
          for (const [app, status] of Object.entries(prowlarrResults)) {
            steps.push({
              step: `Add ${app.charAt(0).toUpperCase() + app.slice(1)} to Prowlarr`,
              status: status === 'configured' || status === 'already_configured' ? 'success' : 'failed',
              details: status
            });
          }
        } catch (e) {
          steps.push({ step: 'Configure Prowlarr apps', status: 'failed', details: e.message });
        }
      }
    }

    // Summary
    const succeeded = steps.filter(s => s.status === 'success').length;
    const failed = steps.filter(s => s.status === 'failed').length;

    if (succeeded > 0) {
      ctx.notification.send(
        'deploymentSuccess',
        'Smart Arr Connect Complete',
        `${succeeded}/${steps.length} steps completed successfully`,
        'success'
      );
    }

    res.json({
      success: succeeded > 0,
      steps,
      summary: { totalSteps: steps.length, succeeded, failed }
    });
  }, 'smart-connect'));

  return router;
};
