import { Injectable, Logger, OnModuleDestroy } from '@nestjs/common';
import { EcoDmsConnector, ConnectorHealth } from './ecodms.connector';
import {
  EcoDmsDocument,
  EcoDmsFolder,
  EcoDmsClassification,
  EcoDmsSearchResult,
  SearchDocumentsDto,
  UploadDocumentDto,
  UpdateDocumentDto,
  ListDocumentsDto,
  CreateFolderDto,
} from './ecodms.types';

/**
 * ecoDMS Service
 *
 * High-level service for interacting with ecoDMS document management system.
 * Wraps the connector with additional business logic and logging.
 */
@Injectable()
export class EcoDmsService implements OnModuleDestroy {
  private readonly logger = new Logger(EcoDmsService.name);

  constructor(private readonly connector: EcoDmsConnector) {}

  /**
   * Cleanup on module destroy
   */
  async onModuleDestroy(): Promise<void> {
    this.logger.log('Cleaning up ecoDMS session');
    await this.connector.logout();
  }

  // ============ Health & Status ============

  /**
   * Check health status of the ecoDMS integration
   */
  async checkHealth(): Promise<ConnectorHealth> {
    this.logger.debug('Checking ecoDMS connector health');
    return this.connector.checkHealth();
  }

  /**
   * Test connection to ecoDMS
   */
  async testConnection(): Promise<{ success: boolean; message: string; latency?: number }> {
    this.logger.log('Testing ecoDMS connection');
    const result = await this.connector.testConnection();
    this.logger.log(`ecoDMS connection test: ${result.success ? 'SUCCESS' : 'FAILED'} - ${result.message}`);
    return result;
  }

  /**
   * Check if connector is configured
   */
  isConfigured(): boolean {
    return this.connector.getIsConfigured();
  }

  // ============ Documents ============

  /**
   * List documents with optional filters
   */
  async listDocuments(params: ListDocumentsDto = {}): Promise<{
    documents: EcoDmsDocument[];
    pagination: { page: number; pageSize: number; total: number; totalPages: number };
  }> {
    this.logger.debug(`Listing documents with params: ${JSON.stringify(params)}`);
    const result = await this.connector.listDocuments(params);
    this.logger.debug(`Found ${result.documents.length} documents`);
    return result;
  }

  /**
   * Get a single document by ID
   */
  async getDocument(id: number): Promise<EcoDmsDocument> {
    this.logger.debug(`Getting document: ${id}`);
    return this.connector.getDocument(id);
  }

  /**
   * Search documents
   */
  async searchDocuments(params: SearchDocumentsDto): Promise<EcoDmsSearchResult> {
    this.logger.log(`Searching documents with query: ${params.query || 'no query'}`);
    const result = await this.connector.searchDocuments(params);
    this.logger.log(`Search returned ${result.totalCount} results in ${result.searchTime}ms`);
    return result;
  }

  /**
   * Upload a document
   */
  async uploadDocument(
    file: Buffer,
    fileName: string,
    mimeType: string,
    metadata: UploadDocumentDto,
  ): Promise<EcoDmsDocument> {
    this.logger.log(`Uploading document: ${metadata.title} (${fileName})`);
    const document = await this.connector.uploadDocument(file, fileName, mimeType, metadata);
    this.logger.log(`Uploaded document: ${document.id} - ${document.docId}`);
    return document;
  }

  /**
   * Update document metadata
   */
  async updateDocument(id: number, data: UpdateDocumentDto): Promise<EcoDmsDocument> {
    this.logger.log(`Updating document: ${id}`);
    const document = await this.connector.updateDocument(id, data);
    this.logger.log(`Updated document: ${document.id}`);
    return document;
  }

  /**
   * Delete a document
   */
  async deleteDocument(id: number): Promise<void> {
    this.logger.log(`Deleting document: ${id}`);
    await this.connector.deleteDocument(id);
    this.logger.log(`Deleted document: ${id}`);
  }

  /**
   * Download document content
   */
  async downloadDocument(id: number): Promise<{ content: Buffer; fileName: string; mimeType: string }> {
    this.logger.debug(`Downloading document: ${id}`);
    const result = await this.connector.downloadDocument(id);
    this.logger.debug(`Downloaded document: ${id} (${result.content.length} bytes)`);
    return result;
  }

  /**
   * Get document preview
   */
  async getDocumentPreview(id: number, page: number = 1): Promise<Buffer> {
    this.logger.debug(`Getting preview for document: ${id}, page: ${page}`);
    return this.connector.getDocumentPreview(id, page);
  }

  /**
   * Find documents by classification
   */
  async findByClassification(classifyId: number, params?: Omit<ListDocumentsDto, 'classifyId'>): Promise<{
    documents: EcoDmsDocument[];
    pagination: { page: number; pageSize: number; total: number; totalPages: number };
  }> {
    this.logger.debug(`Finding documents by classification: ${classifyId}`);
    return this.listDocuments({ ...params, classifyId });
  }

  /**
   * Find documents by folder
   */
  async findByFolder(folderId: number, params?: Omit<ListDocumentsDto, 'folderId'>): Promise<{
    documents: EcoDmsDocument[];
    pagination: { page: number; pageSize: number; total: number; totalPages: number };
  }> {
    this.logger.debug(`Finding documents in folder: ${folderId}`);
    return this.listDocuments({ ...params, folderId });
  }

  /**
   * Quick search documents by text
   */
  async quickSearch(query: string, limit: number = 20): Promise<EcoDmsDocument[]> {
    this.logger.debug(`Quick search: "${query}"`);
    const result = await this.searchDocuments({
      query,
      pageSize: limit,
    });
    return result.documents;
  }

  // ============ Folders ============

  /**
   * List folders
   */
  async listFolders(parentId?: number): Promise<EcoDmsFolder[]> {
    this.logger.debug(`Listing folders${parentId !== undefined ? ` under parent: ${parentId}` : ''}`);
    const folders = await this.connector.listFolders(parentId);
    this.logger.debug(`Found ${folders.length} folders`);
    return folders;
  }

  /**
   * Get folder tree
   */
  async getFolderTree(): Promise<EcoDmsFolder[]> {
    this.logger.debug('Getting folder tree');
    const tree = await this.connector.getFolderTree();
    this.logger.debug('Retrieved folder tree');
    return tree;
  }

  /**
   * Create a folder
   */
  async createFolder(data: CreateFolderDto): Promise<EcoDmsFolder> {
    this.logger.log(`Creating folder: ${data.name}`);
    const folder = await this.connector.createFolder(data);
    this.logger.log(`Created folder: ${folder.id} - ${folder.path}`);
    return folder;
  }

  /**
   * Delete a folder
   */
  async deleteFolder(id: number): Promise<void> {
    this.logger.log(`Deleting folder: ${id}`);
    await this.connector.deleteFolder(id);
    this.logger.log(`Deleted folder: ${id}`);
  }

  /**
   * Ensure a folder exists by path (creates if needed)
   */
  async ensureFolderPath(path: string): Promise<EcoDmsFolder> {
    this.logger.debug(`Ensuring folder path exists: ${path}`);

    const parts = path.split('/').filter(Boolean);
    let parentId: number | undefined;

    for (const part of parts) {
      const folders = await this.listFolders(parentId);
      let folder = folders.find((f) => f.name === part);

      if (!folder) {
        this.logger.log(`Creating missing folder: ${part}`);
        folder = await this.createFolder({ name: part, parentId });
      }

      parentId = folder.id;
    }

    // Return the final folder
    const folders = await this.listFolders(parentId);
    const lastPart = parts[parts.length - 1];
    const finalFolder = folders.find((f) => f.name === lastPart);

    if (!finalFolder) {
      // If we just created it, fetch it
      const allFolders = await this.listFolders(parts.length > 1 ? parentId : undefined);
      return allFolders.find((f) => f.name === lastPart)!;
    }

    return finalFolder;
  }

  // ============ Classifications ============

  /**
   * List all classifications (document types)
   */
  async listClassifications(): Promise<EcoDmsClassification[]> {
    this.logger.debug('Listing classifications');
    const classifications = await this.connector.listClassifications();
    this.logger.debug(`Found ${classifications.length} classifications`);
    return classifications;
  }

  /**
   * Get classification details
   */
  async getClassification(id: number): Promise<EcoDmsClassification> {
    this.logger.debug(`Getting classification: ${id}`);
    return this.connector.getClassification(id);
  }

  /**
   * Find classification by name
   */
  async findClassificationByName(name: string): Promise<EcoDmsClassification | null> {
    this.logger.debug(`Finding classification by name: ${name}`);
    const classifications = await this.listClassifications();
    return classifications.find((c) => c.name.toLowerCase() === name.toLowerCase()) || null;
  }
}
