import matplotlib.pyplot as plt
import numpy as np
import aiohttp
import os
import io
import tkinter as tk
from tkinter import scrolledtext, messagebox as mbox
import asyncio
from fpdf import FPDF
import re
import threading
import logging

# Configure logging
logging.basicConfig(filename='app.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

class URLProcessorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Enhanced E-Paper Grabber")
        self.root.geometry("800x600")
        self.setup_gui()
        self.temp_dir = "temp_images"
        os.makedirs(self.temp_dir, exist_ok=True)
        self.output_dir = os.getcwd()
        self.cleaned_links = []
        self.city_codes = [
            "ALP", "BLR", "CHE", "DEL", "IDK", "KNR", "KGD",
            "CHN", "QLN", "KTM", "CLT", "MPM", "MBY", "PKD",
            "PTA", "TVM", "TCR", "WYND", "BAH", "KWT", "OMAN", "QTR"
        ]

    def setup_gui(self):
        input_frame = tk.Frame(self.root)
        input_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)
        output_frame = tk.Frame(self.root)
        output_frame.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)
        button_frame = tk.Frame(self.root)
        button_frame.pack(pady=10, side=tk.BOTTOM, fill=tk.X)

        self.url_input_area = scrolledtext.ScrolledText(input_frame, wrap=tk.WORD, height=10, width=70, bg='seashell', fg='blue')
        self.url_input_area.pack(fill=tk.BOTH, expand=True)
        self.url_output_area = scrolledtext.ScrolledText(output_frame, wrap=tk.WORD, height=10, width=70, bg='seashell', fg='blue')
        self.url_output_area.pack(fill=tk.BOTH, expand=True)
        self.url_output_area.configure(state=tk.DISABLED)

        self.status_label = tk.Label(self.root, text="")
        self.status_label.pack(pady=10)

        self.create_buttons(button_frame)
        self.create_right_click_menu()

    def create_buttons(self, frame):
        buttons = [
            ("Download", self.start_process, 'green'),
            ("Clear", self.clear_all, 'red'),
            ("Import from Clipboard", self.import_from_clipboard, 'blue'),
            ("Close", self.root.destroy, 'black')
        ]
        for (text, command, color) in buttons:
            tk.Button(frame, text=text, command=command, bg=color, fg='white').pack(pady=5, side=tk.LEFT, padx=10)

    def create_right_click_menu(self):
        self.right_click_menu = tk.Menu(self.root, tearoff=0)
        self.right_click_menu.add_command(label="Paste URL", command=self.paste_url)
        self.url_input_area.bind("<Button-3>", self.show_right_click_menu)

    def start_process(self):
        self.update_status("Starting process...")
        threading.Thread(target=self.process_and_create_pdf).start()

    def process_and_create_pdf(self):
        try:
            self.process_url()
            asyncio.run(self.download_images())
            self.create_pdf()
        except Exception as e:
            self.log_error(f"Error in process: {str(e)}")
        finally:
            self.update_status("PDF generated and saved.")

    def process_url(self):
        input_text = self.url_input_area.get("1.0", tk.END).strip()
        self.cleaned_links = sorted(
            filter(None, (self.clean_url(line.strip()) for line in input_text.splitlines())),
            key=self.extract_page_and_image
        )
        self.update_url_output_area('\n'.join(self.cleaned_links))
        self.update_status(f"Processed Links: {len(self.cleaned_links)}")

    def clean_url(self, url):
        if not url.startswith(("http://", "https://")):
            url = "https://" + url
        if "https://pages-epaper.manoramaonline.com/mmr/" in url:
            return re.sub(r"_tn|_mr", "", url)
        return None

    def extract_page_and_image(self, url):
        page_number, image_number = (
            int(m.group(1)) if m else 0 
            for m in (re.search(r"(\d+)_", url), re.search(r"_(\d+)(?:\.jpg|\.png)", url))
        )
        return page_number, image_number

    async def download_images(self):
        if not self.cleaned_links:
            self.update_status("Please process URLs first.")
            return
        self.clear_temp_dir()
        async with aiohttp.ClientSession() as session:
            for i, link in enumerate(self.cleaned_links):
                await self.download_image(session, link, i + 1)
        self.update_status("All images downloaded.")

    async def download_image(self, session, url, index):
        self.update_status(f"Downloading image {index}/{len(self.cleaned_links)}: {url}")
        try:
            async with session.get(url) as response:
                response.raise_for_status()
                image_data = await response.read()

                # Use matplotlib to process the image
                image_array = plt.imread(io.BytesIO(image_data), format='jpeg')

                # Save the image to temp_dir
                img_path = os.path.join(self.temp_dir, f"image_{index}.jpg")
                plt.imsave(img_path, image_array, format='jpeg')

        except Exception as e:
            self.log_error(f"Error downloading image {index}: {str(e)}")
            mbox.showerror("Download Error", f"Failed to download image {index}")

    def create_pdf(self):
        if not os.listdir(self.temp_dir):
            self.update_status("No images to include in the PDF.")
            return
        pdf_path = os.path.join(self.output_dir, self.generate_filename(self.cleaned_links[0]))
        self.create_pdf_async(pdf_path)

    def create_pdf_async(self, pdf_path):
        try:
            self.create_pdf_with_images(pdf_path)
            self.activate_fast_web_view(pdf_path)
            self.clear_temp_dir()
            self.update_status(f"PDF created and saved at: {pdf_path}")
        except Exception as e:
            self.log_error(f"Error creating PDF: {str(e)}")

    def create_pdf_with_images(self, pdf_path):
        pdf = FPDF()
        for img_file in sorted(os.listdir(self.temp_dir), key=lambda x: int(re.search(r'image_(\d+)', x).group(1))):
            try:
                img_path = os.path.join(self.temp_dir, img_file)
                pdf.add_page()
                self.add_image_to_pdf(pdf, img_path)
            except Exception as e:
                self.log_error(f"Error adding image to PDF: {str(e)}")
        pdf.output(pdf_path, 'F')

    def add_image_to_pdf(self, pdf, img_path):
        pdf_width, pdf_height, margin = 210, 297, 10  # A4 dimensions
        max_width, max_height = pdf_width - 2 * margin, pdf_height - 2 * margin

        image = plt.imread(img_path)
        img_height, img_width, _ = image.shape
        img_ratio = img_width / img_height
        if img_ratio > max_width / max_height:
            scaled_width, scaled_height = max_width, max_width / img_ratio
        else:
            scaled_width, scaled_height = max_height * img_ratio, max_height

        x, y = (pdf_width - scaled_width) / 2, (pdf_height - scaled_height) / 2
        pdf.image(img_path, x, y, scaled_width, scaled_height)

        border_margin = 5
        pdf.set_line_width(0.5)
        pdf.rect(x - border_margin, y - border_margin, scaled_width + 2 * border_margin, scaled_height + 2 * border_margin)

    def activate_fast_web_view(self, pdf_path):
        pass  # Optional: Implement if necessary for fast web viewing

    def generate_filename(self, url):
        city_code = next((code for code in self.city_codes if code.lower() in url.lower()), "")
        base_name = "epaper"

        date_match = re.search(r'(\d{4})[/.-](\d{2})[/.-](\d{2})', url)
        if date_match:
            date = f"{date_match.group(3)}.{date_match.group(2)}.{date_match.group(1)}"
        else:
            date = ""

        filename = f"MM_{city_code}_{base_name}_{date}.pdf".replace('--', '-')
        return filename[:255]  # Ensure filename length constraint

    def update_status(self, message):
        self.status_label.configure(text=message)
        self.root.update_idletasks()

    def log_error(self, message):
        logging.error(message)
        self.update_status(message)

    def clear_all(self):
        self.url_input_area.delete("1.0", tk.END)
        self.update_url_output_area("")
        self.status_label.configure(text="")
        self.clear_temp_dir()

    def update_url_output_area(self, text):
        self.url_output_area.configure(state=tk.NORMAL)
        self.url_output_area.delete("1.0", tk.END)
        self.url_output_area.insert("1.0", text)
        self.url_output_area.configure(state=tk.DISABLED)

    def import_from_clipboard(self):
        try:
            self.url_input_area.insert(tk.END, self.root.clipboard_get())
        except tk.TclError:
            self.update_status("No text found in clipboard.")

    def show_right_click_menu(self, event):
        self.right_click_menu.post(event.x_root, event.y_root)

    def paste_url(self):
        try:
            self.url_input_area.insert(tk.END, self.root.clipboard_get())
        except tk.TclError:
            self.update_status("No text found in clipboard.")

    def clear_temp_dir(self):
        try:
            for file in os.listdir(self.temp_dir):
                os.remove(os.path.join(self.temp_dir, file))
        except Exception as e:
            self.log_error(f"Error clearing temp files: {str(e)}")

# Run the application
if __name__ == "__main__":
    root = tk.Tk()
    app = URLProcessorApp(root)
    root.mainloop()