/*
                        Web-Buddy Framework
                        Google Images Content Script Adapter

    Copyright (C) 2025-today  rydnr@acm-sl.org

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

import { Adapter, listen } from '@typescript-eda/core';
import { 
    GoogleImageDownloadRequested,
    FileDownloadRequested,
    DownloadPatternDetected
} from '../../domain/events/download-events';
import { GoogleImagesDownloader } from '../../domain/entities/google-images-downloader';

/**
 * Google Images Content Adapter - Handles Google Images page interactions
 * 
 * Responsibilities:
 * - Detect Google Images page and inject download functionality
 * - Handle image right-click and download requests
 * - Monitor for new images loaded dynamically
 * - Integrate with training system for pattern learning
 */
export class GoogleImagesContentAdapter extends Adapter {
    private downloader: GoogleImagesDownloader;
    private isGoogleImagesPage: boolean = false;
    private downloadButtons = new Map<HTMLImageElement, HTMLButtonElement>();
    private observer: MutationObserver | null = null;

    constructor() {
        super();
        this.downloader = new GoogleImagesDownloader();
        this.initialize();
    }

    /**
     * Initializes the adapter and checks if we're on Google Images
     */
    private initialize(): void {
        this.isGoogleImagesPage = this.detectGoogleImagesPage();
        
        if (this.isGoogleImagesPage) {
            this.setupGoogleImagesIntegration();
        }
    }

    /**
     * Detects if current page is Google Images
     */
    private detectGoogleImagesPage(): boolean {
        const hostname = window.location.hostname;
        const pathname = window.location.pathname;
        const search = window.location.search;

        return (hostname.includes('google.') && 
                (pathname.includes('/imghp') || 
                 pathname.includes('/search') && search.includes('tbm=isch'))) ||
               document.title.toLowerCase().includes('google images');
    }

    /**
     * Sets up Google Images specific functionality
     */
    private setupGoogleImagesIntegration(): void {
        this.addDownloadButtonsToImages();
        this.setupImageMonitoring();
        this.addContextMenuHandlers();
        this.setupKeyboardShortcuts();
    }

    /**
     * Adds download buttons to visible images
     */
    private addDownloadButtonsToImages(): void {
        const images = this.findGoogleImages();
        
        images.forEach(img => {
            if (!this.downloadButtons.has(img)) {
                this.addDownloadButton(img);
            }
        });
    }

    /**
     * Finds Google Images on the page
     */
    private findGoogleImages(): HTMLImageElement[] {
        const selectors = [
            'img[data-src]', // Lazy loaded images
            'img[src*="googleusercontent.com"]', // Google hosted images
            'img[src*="gstatic.com"]', // Google static images
            '.islrc img', // Images in search results
            '.rg_i', // Result grid images
            'img[jsname]' // Google's internal images
        ];

        const images: HTMLImageElement[] = [];
        
        selectors.forEach(selector => {
            const found = document.querySelectorAll(selector) as NodeListOf<HTMLImageElement>;
            images.push(...Array.from(found));
        });

        // Filter for actual images
        return images.filter(img => {
            return img.src && 
                   (img.naturalWidth > 50 || img.width > 50) && // Minimum size
                   (img.naturalHeight > 50 || img.height > 50);
        });
    }

    /**
     * Adds download button to individual image
     */
    private addDownloadButton(img: HTMLImageElement): void {
        const container = this.createImageContainer(img);
        const downloadButton = this.createDownloadButton(img);
        
        container.appendChild(downloadButton);
        this.downloadButtons.set(img, downloadButton);
        
        // Position the container over the image
        this.positionDownloadButton(img, container);
    }

    /**
     * Creates container for download button
     */
    private createImageContainer(img: HTMLImageElement): HTMLDivElement {
        const container = document.createElement('div');
        container.className = 'web-buddy-download-container';
        container.style.cssText = `
            position: absolute;
            top: 0;
            right: 0;
            z-index: 10000;
            pointer-events: none;
        `;
        
        // Insert container relative to image
        img.parentElement?.appendChild(container);
        
        return container;
    }

    /**
     * Creates download button for image
     */
    private createDownloadButton(img: HTMLImageElement): HTMLButtonElement {
        const button = document.createElement('button');
        button.innerHTML = '📥'; // Download emoji
        button.title = 'Download Image with Web-Buddy';
        button.className = 'web-buddy-download-btn';
        button.style.cssText = `
            background: rgba(0, 0, 0, 0.8);
            color: white;
            border: none;
            border-radius: 4px;
            width: 32px;
            height: 32px;
            cursor: pointer;
            font-size: 16px;
            margin: 4px;
            pointer-events: auto;
            transition: background-color 0.2s;
        `;

        // Hover effects
        button.addEventListener('mouseenter', () => {
            button.style.backgroundColor = 'rgba(0, 0, 0, 1)';
        });

        button.addEventListener('mouseleave', () => {
            button.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
        });

        // Click handler
        button.addEventListener('click', (e) => {
            e.preventDefault();
            e.stopPropagation();
            this.handleImageDownload(img);
        });

        return button;
    }

    /**
     * Positions download button relative to image
     */
    private positionDownloadButton(img: HTMLImageElement, container: HTMLElement): void {
        const updatePosition = () => {
            const imgRect = img.getBoundingClientRect();
            const parentRect = img.parentElement?.getBoundingClientRect();
            
            if (parentRect) {
                container.style.left = `${imgRect.right - parentRect.left - 40}px`;
                container.style.top = `${imgRect.top - parentRect.top + 4}px`;
            }
        };

        // Initial positioning
        updatePosition();

        // Update position on scroll/resize
        window.addEventListener('scroll', updatePosition);
        window.addEventListener('resize', updatePosition);
    }

    /**
     * Sets up monitoring for dynamically loaded images
     */
    private setupImageMonitoring(): void {
        this.observer = new MutationObserver((mutations) => {
            let newImagesFound = false;
            
            mutations.forEach(mutation => {
                if (mutation.type === 'childList') {
                    mutation.addedNodes.forEach(node => {
                        if (node instanceof HTMLImageElement || 
                            (node instanceof HTMLElement && node.querySelector('img'))) {
                            newImagesFound = true;
                        }
                    });
                }
            });

            if (newImagesFound) {
                // Debounce to avoid excessive calls
                setTimeout(() => {
                    this.addDownloadButtonsToImages();
                }, 500);
            }
        });

        this.observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    }

    /**
     * Adds context menu handlers for images
     */
    private addContextMenuHandlers(): void {
        document.addEventListener('contextmenu', (e) => {
            const target = e.target as HTMLElement;
            
            if (target instanceof HTMLImageElement && this.isGoogleImage(target)) {
                this.showCustomContextMenu(e, target);
            }
        });
    }

    /**
     * Checks if image is a Google Images result
     */
    private isGoogleImage(img: HTMLImageElement): boolean {
        return img.src.includes('googleusercontent.com') ||
               img.src.includes('gstatic.com') ||
               img.closest('.islrc, .rg_i') !== null ||
               img.hasAttribute('jsname');
    }

    /**
     * Shows custom context menu with download option
     */
    private showCustomContextMenu(e: MouseEvent, img: HTMLImageElement): void {
        e.preventDefault();
        
        const menu = document.createElement('div');
        menu.className = 'web-buddy-context-menu';
        menu.style.cssText = `
            position: fixed;
            top: ${e.clientY}px;
            left: ${e.clientX}px;
            background: white;
            border: 1px solid #ccc;
            border-radius: 4px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.2);
            z-index: 10001;
            min-width: 200px;
        `;

        const downloadOption = document.createElement('div');
        downloadOption.innerHTML = '📥 Download with Web-Buddy';
        downloadOption.style.cssText = `
            padding: 8px 12px;
            cursor: pointer;
            border-bottom: 1px solid #eee;
        `;

        downloadOption.addEventListener('click', () => {
            this.handleImageDownload(img);
            document.body.removeChild(menu);
        });

        downloadOption.addEventListener('mouseenter', () => {
            downloadOption.style.backgroundColor = '#f5f5f5';
        });

        downloadOption.addEventListener('mouseleave', () => {
            downloadOption.style.backgroundColor = 'white';
        });

        menu.appendChild(downloadOption);
        document.body.appendChild(menu);

        // Remove menu on click outside
        const removeMenu = (e: Event) => {
            if (!menu.contains(e.target as Node)) {
                document.body.removeChild(menu);
                document.removeEventListener('click', removeMenu);
            }
        };

        setTimeout(() => {
            document.addEventListener('click', removeMenu);
        }, 100);
    }

    /**
     * Sets up keyboard shortcuts for downloads
     */
    private setupKeyboardShortcuts(): void {
        document.addEventListener('keydown', (e) => {
            // Ctrl+Shift+D to download focused/hovered image
            if (e.ctrlKey && e.shiftKey && e.key === 'D') {
                e.preventDefault();
                const hoveredImg = this.findHoveredImage();
                if (hoveredImg) {
                    this.handleImageDownload(hoveredImg);
                }
            }
        });
    }

    /**
     * Finds currently hovered image
     */
    private findHoveredImage(): HTMLImageElement | null {
        const elements = document.querySelectorAll(':hover');
        for (let i = elements.length - 1; i >= 0; i--) {
            const element = elements[i];
            if (element instanceof HTMLImageElement && this.isGoogleImage(element)) {
                return element;
            }
        }
        return null;
    }

    /**
     * Handles image download request
     */
    private async handleImageDownload(img: HTMLImageElement): Promise<void> {
        try {
            // Extract search query from page
            const searchQuery = this.extractSearchQuery();
            
            // Create download request event
            const downloadEvent = new GoogleImageDownloadRequested(
                this.generateCorrelationId(),
                {
                    src: img.src,
                    alt: img.alt,
                    title: img.title,
                    width: img.naturalWidth || img.width,
                    height: img.naturalHeight || img.height
                },
                searchQuery
            );

            // Show download feedback
            this.showDownloadFeedback(img, 'Downloading...');

            // Process through downloader entity
            const result = await this.downloader.downloadGoogleImage(downloadEvent);
            
            if (result instanceof FileDownloadRequested) {
                // Send to background script for actual download
                this.sendToBackground({
                    action: 'DOWNLOAD_FILE',
                    payload: {
                        url: result.url,
                        filename: result.filename,
                        conflictAction: result.conflictAction,
                        saveAs: result.saveAs
                    },
                    correlationId: downloadEvent.correlationId
                });

                this.showDownloadFeedback(img, 'Download started!');
            } else {
                this.showDownloadFeedback(img, 'Download failed!', true);
            }

        } catch (error) {
            console.error('Google Images download error:', error);
            this.showDownloadFeedback(img, 'Download error!', true);
        }
    }

    /**
     * Extracts current search query from Google Images page
     */
    private extractSearchQuery(): string {
        // Try to get search query from URL
        const urlParams = new URLSearchParams(window.location.search);
        const query = urlParams.get('q');
        
        if (query) {
            return query;
        }

        // Try to get from search input
        const searchInput = document.querySelector('input[name="q"]') as HTMLInputElement;
        if (searchInput && searchInput.value) {
            return searchInput.value;
        }

        // Try to get from page title
        const title = document.title;
        const match = title.match(/^(.+?)\s*-\s*Google/);
        if (match) {
            return match[1];
        }

        return 'google_search';
    }

    /**
     * Shows visual feedback for download status
     */
    private showDownloadFeedback(img: HTMLImageElement, message: string, isError: boolean = false): void {
        const feedback = document.createElement('div');
        feedback.textContent = message;
        feedback.style.cssText = `
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            background: ${isError ? '#f44336' : '#4CAF50'};
            color: white;
            padding: 8px 12px;
            border-radius: 4px;
            font-size: 12px;
            z-index: 10002;
            pointer-events: none;
            opacity: 0;
            transition: opacity 0.3s;
        `;

        // Position relative to image
        const imgContainer = img.parentElement;
        if (imgContainer) {
            imgContainer.style.position = 'relative';
            imgContainer.appendChild(feedback);
            
            // Animate in
            setTimeout(() => {
                feedback.style.opacity = '1';
            }, 100);

            // Remove after delay
            setTimeout(() => {
                feedback.style.opacity = '0';
                setTimeout(() => {
                    if (feedback.parentElement) {
                        feedback.parentElement.removeChild(feedback);
                    }
                }, 300);
            }, 2000);
        }
    }

    /**
     * Sends message to background script
     */
    private sendToBackground(message: any): void {
        chrome.runtime.sendMessage(message);
    }

    /**
     * Generates unique correlation ID
     */
    private generateCorrelationId(): string {
        return `google-images-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
    }

    /**
     * Cleanup method
     */
    public dispose(): void {
        if (this.observer) {
            this.observer.disconnect();
        }
        
        this.downloadButtons.clear();
        
        // Remove all download containers
        const containers = document.querySelectorAll('.web-buddy-download-container');
        containers.forEach(container => {
            container.parentElement?.removeChild(container);
        });
    }
}