import { Component, Input, OnInit, OnDestroy, OnChanges, SimpleChanges, AfterViewInit, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatCardModule } from '@angular/material/card';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatChipsModule } from '@angular/material/chips';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatExpansionModule } from '@angular/material/expansion';
import { MatTableModule } from '@angular/material/table';
import { MatDialogModule, MatDialog } from '@angular/material/dialog';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { Subject } from 'rxjs';
import * as pdfjsLib from 'pdfjs-dist';
import { StorageService } from '../../../core/services/storage.service';
import { RuntimeConfigService } from '../../../core/services/runtime-config.service';

interface DocumentVersion {
  id: string;
  version: number;
  fileHash: string;
  uploadedAt: string;
  uploadedBy: string;
  changes?: string;
}

interface DepartmentReview {
  departmentCode: string;
  departmentName: string;
  reviewedAt: string;
  reviewedBy: string;
  status: 'APPROVED' | 'REJECTED' | 'PENDING';
  comments?: string;
}

interface Document {
  id: string;
  name: string;
  type: string;
  size: number;
  fileHash: string;
  ipfsHash?: string;
  url: string;
  thumbnailUrl?: string;
  previewDataUrl?: string; // Generated preview data URL
  previewLoading?: boolean;
  previewError?: boolean;
  mimeType?: string;
  uploadedAt: string;
  uploadedBy: string;
  currentVersion: number;
  versions?: DocumentVersion[];
  departmentReviews?: DepartmentReview[];
  metadata?: {
    mimeType: string;
    width?: number;
    height?: number;
    pages?: number;
  };
}

@Component({
  selector: 'app-document-viewer',
  standalone: true,
  imports: [
    CommonModule,
    MatCardModule,
    MatButtonModule,
    MatIconModule,
    MatChipsModule,
    MatTooltipModule,
    MatExpansionModule,
    MatTableModule,
    MatDialogModule,
    MatProgressSpinnerModule,
  ],
  template: `
    <div class="document-viewer">
      <div class="documents-grid" *ngIf="documents && documents.length > 0">
        <mat-card *ngFor="let doc of documents" class="document-card">
          <!-- Document Thumbnail/Preview -->
          <div class="document-thumbnail"
               [class.has-thumbnail]="doc.previewDataUrl || doc.thumbnailUrl"
               [class.is-loading]="doc.previewLoading"
               (click)="previewDocument(doc)">
            <!-- Loading spinner -->
            <div *ngIf="doc.previewLoading" class="preview-loading">
              <mat-spinner diameter="40"></mat-spinner>
              <span>Loading preview...</span>
            </div>
            <!-- Actual preview image -->
            <img *ngIf="(doc.previewDataUrl || doc.thumbnailUrl) && !doc.previewLoading"
                 [src]="doc.previewDataUrl || doc.thumbnailUrl"
                 [alt]="doc.name"
                 class="preview-image" />
            <!-- Fallback icon when no preview available -->
            <div *ngIf="!doc.previewDataUrl && !doc.thumbnailUrl && !doc.previewLoading" class="document-icon">
              <mat-icon>{{ getFileIcon(doc.type) }}</mat-icon>
              <span class="file-extension">{{ getFileExtension(doc.name) }}</span>
            </div>
            <!-- Hover overlay -->
            <div class="preview-overlay">
              <mat-icon>visibility</mat-icon>
              <span>Preview</span>
            </div>
          </div>

          <!-- Document Info -->
          <mat-card-content>
            <div class="document-header">
              <h3 class="document-name" [matTooltip]="doc.name">{{ doc.name }}</h3>
              <mat-chip class="version-chip">v{{ doc.currentVersion }}</mat-chip>
            </div>

            <div class="document-meta">
              <div class="meta-item">
                <mat-icon>storage</mat-icon>
                <span>{{ formatFileSize(doc.size) }}</span>
              </div>
              <div class="meta-item">
                <mat-icon>schedule</mat-icon>
                <span>{{ doc.uploadedAt | date:'short' }}</span>
              </div>
            </div>

            <!-- Document Hash -->
            <div class="document-hash" *ngIf="doc.fileHash">
              <div class="hash-label">
                <mat-icon>fingerprint</mat-icon>
                <span>File Hash:</span>
              </div>
              <code class="hash-value" [matTooltip]="doc.fileHash">
                {{ doc.fileHash | slice:0:16 }}...{{ doc.fileHash | slice:-12 }}
              </code>
              <button mat-icon-button (click)="copyToClipboard(doc.fileHash)" matTooltip="Copy hash">
                <mat-icon>content_copy</mat-icon>
              </button>
            </div>

            <!-- IPFS Hash -->
            <div class="document-hash" *ngIf="doc.ipfsHash">
              <div class="hash-label">
                <mat-icon>cloud</mat-icon>
                <span>IPFS:</span>
              </div>
              <code class="hash-value" [matTooltip]="doc.ipfsHash">
                {{ doc.ipfsHash | slice:0:16 }}...{{ doc.ipfsHash | slice:-12 }}
              </code>
            </div>

            <!-- Department Reviews -->
            <div class="department-reviews" *ngIf="doc.departmentReviews && doc.departmentReviews.length > 0">
              <div class="reviews-header">
                <mat-icon>fact_check</mat-icon>
                <span>Department Reviews</span>
              </div>
              <div class="reviews-list">
                <div *ngFor="let review of doc.departmentReviews" class="review-item">
                  <div class="review-dept">{{ review.departmentName }}</div>
                  <mat-chip
                    [style.background-color]="getReviewStatusColor(review.status)"
                    [style.color]="'white'"
                  >
                    {{ review.status }}
                  </mat-chip>
                </div>
              </div>
            </div>

            <!-- Action Buttons -->
            <div class="document-actions">
              <button mat-button color="primary" (click)="downloadDocument(doc)">
                <mat-icon>download</mat-icon>
                Download
              </button>
              <button mat-button (click)="previewDocument(doc)">
                <mat-icon>visibility</mat-icon>
                Preview
              </button>
              <button
                mat-button
                *ngIf="doc.versions && doc.versions.length > 1"
                (click)="viewVersionHistory(doc)"
              >
                <mat-icon>history</mat-icon>
                History ({{ doc.versions.length }})
              </button>
            </div>

            <!-- Version History (Expandable) -->
            <mat-expansion-panel *ngIf="doc.versions && doc.versions.length > 1" class="version-history">
              <mat-expansion-panel-header>
                <mat-panel-title>
                  <mat-icon>history</mat-icon>
                  Version History ({{ doc.versions.length }} versions)
                </mat-panel-title>
              </mat-expansion-panel-header>

              <table mat-table [dataSource]="doc.versions" class="version-table">
                <ng-container matColumnDef="version">
                  <th mat-header-cell *matHeaderCellDef>Version</th>
                  <td mat-cell *matCellDef="let version">
                    <strong>v{{ version.version }}</strong>
                  </td>
                </ng-container>

                <ng-container matColumnDef="uploadedAt">
                  <th mat-header-cell *matHeaderCellDef>Date</th>
                  <td mat-cell *matCellDef="let version">
                    {{ version.uploadedAt | date:'short' }}
                  </td>
                </ng-container>

                <ng-container matColumnDef="uploadedBy">
                  <th mat-header-cell *matHeaderCellDef>Uploaded By</th>
                  <td mat-cell *matCellDef="let version">
                    {{ version.uploadedBy }}
                  </td>
                </ng-container>

                <ng-container matColumnDef="fileHash">
                  <th mat-header-cell *matHeaderCellDef>Hash</th>
                  <td mat-cell *matCellDef="let version">
                    <code class="small-hash">{{ version.fileHash | slice:0:8 }}...</code>
                  </td>
                </ng-container>

                <ng-container matColumnDef="actions">
                  <th mat-header-cell *matHeaderCellDef>Actions</th>
                  <td mat-cell *matCellDef="let version">
                    <button mat-icon-button (click)="downloadVersion(doc, version)" matTooltip="Download this version">
                      <mat-icon>download</mat-icon>
                    </button>
                  </td>
                </ng-container>

                <tr mat-header-row *matHeaderRowDef="versionColumns"></tr>
                <tr mat-row *matRowDef="let row; columns: versionColumns"></tr>
              </table>
            </mat-expansion-panel>
          </mat-card-content>
        </mat-card>
      </div>

      <!-- No Documents Message -->
      <div *ngIf="!documents || documents.length === 0" class="no-documents">
        <mat-icon>folder_open</mat-icon>
        <p>No documents uploaded</p>
      </div>
    </div>
  `,
  styles: [
    `
      .document-viewer {
        padding: 16px 0;
      }

      .documents-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
        gap: 24px;
      }

      .document-card {
        display: flex;
        flex-direction: column;
        transition: transform 0.2s, box-shadow 0.2s;

        &:hover {
          transform: translateY(-4px);
          box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
        }
      }

      .document-thumbnail {
        position: relative;
        width: 100%;
        height: 200px;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        overflow: hidden;
        border-radius: 8px 8px 0 0;

        &.has-thumbnail {
          background: #f8f9fa;
        }

        &.is-loading {
          background: #e9ecef;
        }

        .preview-loading {
          display: flex;
          flex-direction: column;
          align-items: center;
          gap: 12px;
          color: #666;

          span {
            font-size: 0.875rem;
          }
        }

        .preview-image {
          width: 100%;
          height: 100%;
          object-fit: contain;
          background: white;
          padding: 8px;
        }

        .document-icon {
          display: flex;
          flex-direction: column;
          align-items: center;
          gap: 8px;
          color: white;

          mat-icon {
            font-size: 64px;
            width: 64px;
            height: 64px;
          }

          .file-extension {
            font-size: 1.25rem;
            font-weight: 600;
            text-transform: uppercase;
          }
        }

        .preview-overlay {
          position: absolute;
          top: 0;
          left: 0;
          right: 0;
          bottom: 0;
          background: rgba(0, 0, 0, 0.7);
          display: flex;
          flex-direction: column;
          align-items: center;
          justify-content: center;
          gap: 8px;
          opacity: 0;
          transition: opacity 0.2s;
          color: white;

          mat-icon {
            font-size: 48px;
            width: 48px;
            height: 48px;
          }
        }

        &:hover .preview-overlay {
          opacity: 1;
        }
      }

      mat-card-content {
        padding: 16px !important;
      }

      .document-header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 12px;
        margin-bottom: 12px;
      }

      .document-name {
        margin: 0;
        font-size: 1rem;
        font-weight: 500;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        flex: 1;
      }

      .version-chip {
        flex-shrink: 0;
        background-color: #e3f2fd !important;
        color: #1565c0 !important;
        font-weight: 600;
      }

      .document-meta {
        display: flex;
        gap: 16px;
        margin-bottom: 12px;
      }

      .meta-item {
        display: flex;
        align-items: center;
        gap: 6px;
        font-size: 0.875rem;
        color: #666;

        mat-icon {
          font-size: 18px;
          width: 18px;
          height: 18px;
        }
      }

      .document-hash {
        display: flex;
        align-items: center;
        gap: 8px;
        padding: 8px;
        background-color: #f5f5f5;
        border-radius: 4px;
        margin-bottom: 8px;

        .hash-label {
          display: flex;
          align-items: center;
          gap: 6px;
          font-size: 0.75rem;
          font-weight: 500;
          color: #666;

          mat-icon {
            font-size: 16px;
            width: 16px;
            height: 16px;
          }
        }

        .hash-value {
          flex: 1;
          font-family: monospace;
          font-size: 0.75rem;
          background-color: white;
          padding: 4px 8px;
          border-radius: 4px;
          overflow: hidden;
          text-overflow: ellipsis;
          white-space: nowrap;
        }

        button {
          flex-shrink: 0;
        }
      }

      .department-reviews {
        margin: 16px 0;
        padding: 12px;
        background-color: #f5f5f5;
        border-radius: 4px;
      }

      .reviews-header {
        display: flex;
        align-items: center;
        gap: 8px;
        font-size: 0.875rem;
        font-weight: 500;
        margin-bottom: 12px;
        color: #666;

        mat-icon {
          font-size: 18px;
          width: 18px;
          height: 18px;
        }
      }

      .reviews-list {
        display: flex;
        flex-direction: column;
        gap: 8px;
      }

      .review-item {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 12px;
        padding: 8px;
        background-color: white;
        border-radius: 4px;
      }

      .review-dept {
        font-size: 0.875rem;
        font-weight: 500;
        flex: 1;
      }

      .document-actions {
        display: flex;
        gap: 8px;
        margin-top: 16px;
        flex-wrap: wrap;

        button {
          display: flex;
          align-items: center;
          gap: 6px;
        }
      }

      .version-history {
        margin-top: 16px;
      }

      .version-table {
        width: 100%;
        margin-top: 8px;

        .small-hash {
          font-size: 0.75rem;
        }
      }

      .no-documents {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        padding: 60px 20px;
        color: #999;

        mat-icon {
          font-size: 64px;
          width: 64px;
          height: 64px;
          margin-bottom: 16px;
        }

        p {
          margin: 0;
          font-size: 1.125rem;
        }
      }
    `,
  ],
})
export class DocumentViewerComponent implements OnInit, OnDestroy, AfterViewInit, OnChanges {
  @Input() documents: Document[] = [];
  @Input() showVersionHistory = true;
  @Input() showDepartmentReviews = true;
  @Input() apiBaseUrl?: string;

  versionColumns = ['version', 'uploadedAt', 'uploadedBy', 'fileHash', 'actions'];

  private destroy$ = new Subject<void>();
  private storage = inject(StorageService);
  private configService = inject(RuntimeConfigService);

  /**
   * Get effective API base URL (input override or runtime config)
   */
  private get effectiveApiBaseUrl(): string {
    return this.apiBaseUrl || this.configService.apiBaseUrl;
  }

  constructor(private dialog: MatDialog) {
    // Configure PDF.js worker - use local asset
    pdfjsLib.GlobalWorkerOptions.workerSrc = '/assets/pdf.worker.min.js';
  }

  ngOnInit(): void {
    // Load previews after documents are set
    this.loadDocumentPreviews();
  }

  ngAfterViewInit(): void {
    // Ensure previews are loaded after view is ready
    setTimeout(() => this.loadDocumentPreviews(), 100);
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }

  private loadDocumentPreviews(): void {
    if (!this.documents?.length) return;

    this.documents.forEach(doc => {
      if (!doc.previewDataUrl && !doc.previewLoading) {
        this.generatePreview(doc);
      }
    });
  }

  private generatePreview(doc: Document): void {
    const mimeType = doc.mimeType || doc.metadata?.mimeType || this.getMimeTypeFromFilename(doc.name);

    if (this.isImage(mimeType)) {
      this.loadImagePreview(doc);
    } else if (this.isPdf(mimeType)) {
      this.loadPdfPreview(doc);
    }
    // Other file types will show the default icon
  }

  private getMimeTypeFromFilename(filename: string): string {
    const ext = filename?.split('.').pop()?.toLowerCase() || '';
    const mimeMap: { [key: string]: string } = {
      'pdf': 'application/pdf',
      'jpg': 'image/jpeg',
      'jpeg': 'image/jpeg',
      'png': 'image/png',
      'gif': 'image/gif',
      'webp': 'image/webp',
      'bmp': 'image/bmp',
      'svg': 'image/svg+xml',
    };
    return mimeMap[ext] || 'application/octet-stream';
  }

  private isImage(mimeType: string): boolean {
    return mimeType?.startsWith('image/') || false;
  }

  private isPdf(mimeType: string): boolean {
    return mimeType === 'application/pdf';
  }

  private async loadImagePreview(doc: Document): Promise<void> {
    doc.previewLoading = true;
    const downloadUrl = `${this.effectiveApiBaseUrl}/documents/${doc.id}/download?inline=true`;

    try {
      // Get authorization token
      const token = this.storage.getToken();
      const headers: HeadersInit = {};
      if (token) {
        headers['Authorization'] = `Bearer ${token}`;
      }

      // Use fetch with authorization header
      const response = await fetch(downloadUrl, {
        credentials: 'include',
        headers
      });

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }

      const blob = await response.blob();

      // Convert blob to data URL
      const reader = new FileReader();
      reader.onload = () => {
        doc.previewDataUrl = reader.result as string;
        doc.previewLoading = false;
      };
      reader.onerror = () => {
        console.warn('Failed to read image blob:', reader.error);
        doc.previewLoading = false;
        doc.previewError = true;
      };
      reader.readAsDataURL(blob);
    } catch (err) {
      console.warn('Image preview failed, using fallback icon:', err);
      doc.previewLoading = false;
      doc.previewError = true;
    }
  }

  private async loadPdfPreview(doc: Document): Promise<void> {
    doc.previewLoading = true;
    const downloadUrl = `${this.effectiveApiBaseUrl}/documents/${doc.id}/download`;

    try {
      // Get authorization token
      const token = this.storage.getToken();
      const headers: HeadersInit = {};
      if (token) {
        headers['Authorization'] = `Bearer ${token}`;
      }

      // Fetch the PDF as an array buffer
      const response = await fetch(downloadUrl, {
        credentials: 'include',
        headers
      });

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }

      const arrayBuffer = await response.arrayBuffer();

      // Load PDF and render first page
      const pdf = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
      const page = await pdf.getPage(1);

      // Create a canvas for the thumbnail - scale to fit 320x200
      const originalViewport = page.getViewport({ scale: 1 });
      const scale = Math.min(320 / originalViewport.width, 200 / originalViewport.height);
      const viewport = page.getViewport({ scale });

      const canvas = document.createElement('canvas');
      canvas.width = viewport.width;
      canvas.height = viewport.height;

      const ctx = canvas.getContext('2d');
      if (!ctx) {
        throw new Error('Could not get canvas context');
      }

      // Fill white background
      ctx.fillStyle = 'white';
      ctx.fillRect(0, 0, canvas.width, canvas.height);

      // Render the page
      await page.render({
        canvasContext: ctx,
        viewport
      }).promise;

      // Convert to data URL
      doc.previewDataUrl = canvas.toDataURL('image/png');
      doc.previewLoading = false;
    } catch (err) {
      // If PDF.js fails, still mark as done but use fallback icon
      console.warn('PDF preview failed, using fallback icon:', err);
      doc.previewLoading = false;
      doc.previewError = true;
      // Don't set previewDataUrl - will show default icon
    }
  }

  getFileIcon(type: string): string {
    const iconMap: { [key: string]: string } = {
      pdf: 'picture_as_pdf',
      image: 'image',
      video: 'videocam',
      audio: 'audiotrack',
      document: 'description',
      spreadsheet: 'table_chart',
      presentation: 'slideshow',
      archive: 'archive',
    };
    return iconMap[type] || 'insert_drive_file';
  }

  getFileExtension(filename: string | undefined | null): string {
    if (!filename) return 'FILE';
    const parts = filename.split('.');
    return parts.length > 1 ? parts[parts.length - 1].toUpperCase() : 'FILE';
  }

  formatFileSize(bytes: number): string {
    if (bytes === 0) return '0 Bytes';
    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
  }

  getReviewStatusColor(status: string): string {
    const colors: { [key: string]: string } = {
      APPROVED: '#4caf50',
      REJECTED: '#f44336',
      PENDING: '#ff9800',
    };
    return colors[status] || '#757575';
  }

  copyToClipboard(text: string): void {
    navigator.clipboard.writeText(text).then(() => {
      alert('Hash copied to clipboard!');
    });
  }

  downloadDocument(doc: Document): void {
    const downloadUrl = `${this.effectiveApiBaseUrl}/documents/${doc.id}/download`;
    // Open in new tab to trigger download
    window.open(downloadUrl, '_blank');
  }

  downloadVersion(doc: Document, version: DocumentVersion): void {
    const downloadUrl = `${this.effectiveApiBaseUrl}/documents/${doc.id}/download?version=${version.version}`;
    window.open(downloadUrl, '_blank');
  }

  previewDocument(doc: Document): void {
    const mimeType = doc.mimeType || doc.metadata?.mimeType || this.getMimeTypeFromFilename(doc.name);
    const previewUrl = `${this.effectiveApiBaseUrl}/documents/${doc.id}/download?inline=true`;

    if (this.isImage(mimeType) || this.isPdf(mimeType)) {
      // Open in new window with inline display
      window.open(previewUrl, '_blank', 'width=900,height=700,scrollbars=yes');
    } else {
      // For other types, trigger download
      this.downloadDocument(doc);
    }
  }

  viewVersionHistory(doc: Document): void {
    alert(`Version History for ${doc.name}\n\nTotal versions: ${doc.versions?.length}`);
  }

  // Called when documents input changes
  ngOnChanges(changes: SimpleChanges): void {
    if (changes['documents'] && !changes['documents'].firstChange) {
      this.loadDocumentPreviews();
    }
  }
}
