import { Injectable, Logger, NotFoundException } from '@nestjs/common';
import { PlentyoneService } from './connectors/plentyone/plentyone.service';
import { PlentyoneConnector } from './connectors/plentyone/plentyone.connector';
import { ZulipService } from './connectors/zulip/zulip.service';
import { ZulipConnector } from './connectors/zulip/zulip.connector';
import { TodoistService } from './connectors/todoist/todoist.service';
import { TodoistConnector } from './connectors/todoist/todoist.connector';
import { FreeScoutService } from './connectors/freescout/freescout.service';
import { FreeScoutConnector } from './connectors/freescout/freescout.connector';
import { NextcloudService } from './connectors/nextcloud/nextcloud.service';
import { NextcloudConnector } from './connectors/nextcloud/nextcloud.connector';
import { EcoDmsService } from './connectors/ecodms/ecodms.service';
import { EcoDmsConnector } from './connectors/ecodms/ecodms.connector';
import { GembaDocsService } from './connectors/gembadocs/gembadocs.service';
import { GembaDocsConnector } from './connectors/gembadocs/gembadocs.connector';
import {
  IntegrationStatusDto,
  IntegrationsOverviewDto,
  IntegrationHealthDto,
} from './dto';

/**
 * Supported integration types
 */
export type IntegrationType =
  | 'plentyone'
  | 'zulip'
  | 'todoist'
  | 'freescout'
  | 'nextcloud'
  | 'ecodms'
  | 'gembadocs';

/**
 * Integration metadata
 */
interface IntegrationMeta {
  type: IntegrationType;
  name: string;
  description: string;
}

/**
 * Service for managing all integrations
 *
 * Provides aggregated status, health checks, and overview functionality.
 */
@Injectable()
export class IntegrationsService {
  private readonly logger = new Logger(IntegrationsService.name);

  /**
   * Metadata for all available integrations
   */
  private readonly integrationsMeta: IntegrationMeta[] = [
    {
      type: 'plentyone',
      name: 'PlentyONE',
      description: 'E-commerce platform integration for orders and stock management',
    },
    {
      type: 'zulip',
      name: 'ZULIP',
      description: 'Team chat integration for messaging and notifications',
    },
    {
      type: 'todoist',
      name: 'Todoist',
      description: 'Task management integration for projects and tasks',
    },
    {
      type: 'freescout',
      name: 'FreeScout',
      description: 'Helpdesk and ticketing system integration',
    },
    {
      type: 'nextcloud',
      name: 'Nextcloud',
      description: 'Cloud file storage and collaboration platform',
    },
    {
      type: 'ecodms',
      name: 'ecoDMS',
      description: 'Document management system integration',
    },
    {
      type: 'gembadocs',
      name: 'GembaDocs',
      description: 'Audit and compliance documentation management',
    },
  ];

  constructor(
    private readonly plentyoneService: PlentyoneService,
    private readonly plentyoneConnector: PlentyoneConnector,
    private readonly zulipService: ZulipService,
    private readonly zulipConnector: ZulipConnector,
    private readonly todoistService: TodoistService,
    private readonly todoistConnector: TodoistConnector,
    private readonly freescoutService: FreeScoutService,
    private readonly freescoutConnector: FreeScoutConnector,
    private readonly nextcloudService: NextcloudService,
    private readonly nextcloudConnector: NextcloudConnector,
    private readonly ecodmsService: EcoDmsService,
    private readonly ecodmsConnector: EcoDmsConnector,
    private readonly gembaDocsService: GembaDocsService,
    private readonly gembaDocsConnector: GembaDocsConnector,
  ) {}

  /**
   * Get overview of all integrations with their status
   */
  async getOverview(): Promise<IntegrationsOverviewDto> {
    this.logger.log('Fetching integrations overview');

    const integrations: IntegrationStatusDto[] = [];

    const allTypes: IntegrationType[] = [
      'plentyone', 'zulip', 'todoist', 'freescout', 'nextcloud', 'ecodms', 'gembadocs',
    ];

    // Check each integration in parallel
    const results = await Promise.allSettled(
      allTypes.map((type) => this.getIntegrationStatus(type)),
    );

    for (const result of results) {
      if (result.status === 'fulfilled') {
        integrations.push(result.value);
      }
    }

    const configuredCount = integrations.filter((i) => i.configured).length;
    const connectedCount = integrations.filter((i) => i.connected).length;

    return {
      integrations,
      configuredCount,
      connectedCount,
      totalCount: integrations.length,
    };
  }

  /**
   * Get status for a specific integration
   */
  async getIntegrationStatus(type: IntegrationType): Promise<IntegrationStatusDto> {
    const meta = this.integrationsMeta.find((m) => m.type === type);
    if (!meta) {
      throw new NotFoundException(`Integration type '${type}' not found`);
    }

    const status: IntegrationStatusDto = {
      type: meta.type,
      name: meta.name,
      configured: false,
      connected: false,
    };

    try {
      const { service, connector } = this.getServiceAndConnector(type);

      // Ensure credentials are loaded from DB before checking configured state
      await connector.ensureInitialized();

      status.configured = service.isConfigured();

      if (!status.configured) {
        if (connector.getMissingConfig) {
          status.missingConfig = connector.getMissingConfig();
        }
        return status;
      }

      // Test connection
      const result = await service.testConnection();
      status.connected = result.success;
      status.lastChecked = new Date().toISOString();
      status.latencyMs = result.latencyMs;

      if (!result.success) {
        status.error = result.message;
      }
    } catch (error) {
      status.connected = false;
      status.error = error instanceof Error ? error.message : 'Unknown error';
      status.lastChecked = new Date().toISOString();
    }

    return status;
  }

  /**
   * Perform a health check on a specific integration
   */
  async checkHealth(type: IntegrationType): Promise<IntegrationHealthDto> {
    const meta = this.integrationsMeta.find((m) => m.type === type);
    if (!meta) {
      throw new NotFoundException(`Integration type '${type}' not found`);
    }

    this.logger.log(`Checking health for ${meta.name}`);

    try {
      const { service, connector } = this.getServiceAndConnector(type);

      // Ensure credentials are loaded from DB before checking configured state
      await connector.ensureInitialized();

      if (!service.isConfigured()) {
        return {
          type: meta.type,
          healthy: false,
          message: 'Integration is not configured',
          timestamp: new Date().toISOString(),
        };
      }

      const result = await service.testConnection();

      return {
        type: meta.type,
        healthy: result.success,
        message: result.message,
        latencyMs: result.latencyMs,
        timestamp: new Date().toISOString(),
        details: result.details,
      };
    } catch (error) {
      return {
        type: meta.type,
        healthy: false,
        message: error instanceof Error ? error.message : 'Unknown error',
        timestamp: new Date().toISOString(),
      };
    }
  }

  /**
   * Get list of available integration types
   */
  getAvailableIntegrations(): IntegrationMeta[] {
    return this.integrationsMeta;
  }

  /**
   * Get service and connector for a specific integration type
   */
  private getServiceAndConnector(type: IntegrationType): {
    service: { isConfigured: () => boolean; testConnection: () => Promise<{ success: boolean; message: string; latencyMs?: number; details?: Record<string, unknown> }> };
    connector: { ensureInitialized: () => Promise<void>; getMissingConfig?: () => string[] };
  } {
    switch (type) {
      case 'plentyone':
        return {
          service: this.plentyoneService,
          connector: this.plentyoneConnector,
        };
      case 'zulip':
        return {
          service: this.zulipService,
          connector: this.zulipConnector,
        };
      case 'todoist':
        return {
          service: this.todoistService,
          connector: this.todoistConnector,
        };
      case 'freescout':
        return {
          service: this.freescoutService,
          connector: this.freescoutConnector as { ensureInitialized: () => Promise<void>; getMissingConfig?: () => string[] },
        };
      case 'nextcloud':
        return {
          service: this.nextcloudService,
          connector: this.nextcloudConnector as { ensureInitialized: () => Promise<void>; getMissingConfig?: () => string[] },
        };
      case 'ecodms':
        return {
          service: this.ecodmsService,
          connector: this.ecodmsConnector as { ensureInitialized: () => Promise<void>; getMissingConfig?: () => string[] },
        };
      case 'gembadocs':
        return {
          service: this.gembaDocsService,
          connector: this.gembaDocsConnector,
        };
      default:
        throw new NotFoundException(`Integration type '${type}' not found`);
    }
  }
}
