import streamlit as st
import os
import PyPDF2
import tempfile
import shutil
from pathlib import Path
import math
import time
import subprocess
import sys

def compress_pdf(input_file, output_file, compression_level=2):
    """Compress a PDF file using Ghostscript if available, or PyPDF2 if not"""
    try:
        # First try using Ghostscript for better compression if available
        gs_command = None
        if sys.platform == 'win32':
            gs_command = ['gswin64c', '-sDEVICE=pdfwrite', f'-dPDFSETTINGS=/ebook',
                         '-dCompatibilityLevel=1.4', '-dNOPAUSE', '-dQUIET', '-dBATCH',
                         f'-sOutputFile={output_file}', input_file]
        else:
            gs_command = ['gs', '-sDEVICE=pdfwrite', f'-dPDFSETTINGS=/ebook',
                         '-dCompatibilityLevel=1.4', '-dNOPAUSE', '-dQUIET', '-dBATCH',
                         f'-sOutputFile={output_file}', input_file]
        
        result = subprocess.run(gs_command, check=True, stderr=subprocess.PIPE)
        return True
    except (subprocess.SubprocessError, FileNotFoundError):
        # Fallback to PyPDF2 (less effective compression)
        try:
            reader = PyPDF2.PdfReader(input_file)
            writer = PyPDF2.PdfWriter()
            
            # Add all pages with reduced quality
            for page in reader.pages:
                writer.add_page(page)
            
            # Set compression parameters
            writer.add_metadata(reader.metadata)
            
            with open(output_file, 'wb') as f_out:
                writer.write(f_out)
            return True
        except Exception as e:
            st.error(f"Compression failed: {str(e)}")
            return False

def split_pdf_fast_with_compression(input_file, target_size_mb=100):
    """Split a PDF file into multiple files and compress those that exceed target size"""
    # Get the total size of the input file in MB
    total_size_mb = os.path.getsize(input_file) / (1024 * 1024)
    
    if total_size_mb <= target_size_mb:
        st.info(f"File is already smaller than {target_size_mb}MB. No need to split.")
        return []
    
    original_filename = os.path.basename(input_file)
    filename_without_ext = os.path.splitext(original_filename)[0]
    
    # Create a temporary directory to store output files
    with tempfile.TemporaryDirectory() as temp_dir:
        # Open the PDF file
        with open(input_file, 'rb') as file:
            pdf_reader = PyPDF2.PdfReader(file)
            total_pages = len(pdf_reader.pages)
            
            # Calculate number of chunks needed
            num_chunks = math.ceil(total_size_mb / target_size_mb)
            
            # Calculate approximately how many pages per chunk (evenly distributed)
            pages_per_chunk = math.ceil(total_pages / num_chunks)
            
            output_files = []
            
            # Process chunks
            for chunk_number in range(1, num_chunks + 1):
                start_page = (chunk_number - 1) * pages_per_chunk
                end_page = min(chunk_number * pages_per_chunk, total_pages)
                
                if start_page >= total_pages:
                    break
                
                # Create a new PDF writer for this chunk
                pdf_writer = PyPDF2.PdfWriter()
                
                # Add pages to this chunk
                for page_num in range(start_page, end_page):
                    pdf_writer.add_page(pdf_reader.pages[page_num])
                
                # Generate output file name
                output_file = os.path.join(temp_dir, f"{filename_without_ext}({chunk_number}).pdf")
                
                # Write the PDF to the output file
                with open(output_file, 'wb') as output:
                    pdf_writer.write(output)
                
                # Calculate the actual size of the output file
                actual_size_mb = os.path.getsize(output_file) / (1024 * 1024)
                
                # Check if the file exceeds the target size and needs compression
                if actual_size_mb > target_size_mb:
                    compressed_file = os.path.join(temp_dir, f"{filename_without_ext}({chunk_number})_compressed.pdf")
                    if compress_pdf(output_file, compressed_file):
                        compressed_size_mb = os.path.getsize(compressed_file) / (1024 * 1024)
                        
                        # Use the compressed file if it's smaller
                        if compressed_size_mb < actual_size_mb:
                            os.replace(compressed_file, output_file)
                            actual_size_mb = compressed_size_mb
                
                # Add the output file to the list
                output_files.append({
                    'path': output_file,
                    'filename': f"{filename_without_ext}({chunk_number}).pdf",
                    'size_mb': actual_size_mb,
                    'pages': end_page - start_page,
                    'compressed': actual_size_mb > target_size_mb
                })
        
        # Copy files to a location outside the temporary directory
        permanent_files = []
        output_dir = os.path.dirname(input_file)
        
        for file_info in output_files:
            dest_path = os.path.join(output_dir, file_info['filename'])
            shutil.copy2(file_info['path'], dest_path)
            file_info['path'] = dest_path
            permanent_files.append(file_info)
        
        return permanent_files

def main():
    st.title("Large PDF Splitter")
    st.write("Upload a large PDF file to split it into smaller chunks")
    
    max_chunk_size = st.slider("Maximum size per chunk (MB)", min_value=10, max_value=500, value=100, step=10)
    
    uploaded_file = st.file_uploader("Choose a PDF file", type="pdf")
    
    if uploaded_file is not None:
        # Create a temporary file to save the uploaded file
        with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as tmp_file:
            with st.spinner("Processing uploaded file..."):
                tmp_file.write(uploaded_file.getvalue())
                tmp_file_path = tmp_file.name
        
        # Preserve the original filename
        original_filename = uploaded_file.name
        
        file_size_mb = os.path.getsize(tmp_file_path) / (1024 * 1024)
        
        st.write(f"Uploaded file: {original_filename}")
        st.write(f"File size: {file_size_mb:.2f} MB")
        
        if st.button("Split File"):
            if file_size_mb <= max_chunk_size:
                st.warning(f"The file is already smaller than {max_chunk_size}MB. No need to split.")
            else:
                start_time = time.time()
                with st.spinner(f"Splitting {original_filename} into chunks and compressing if needed..."):
                    output_files = split_pdf_fast_with_compression(tmp_file_path, max_chunk_size)
                end_time = time.time()
                
                if output_files:
                    processing_time = end_time - start_time
                    st.success(f"Successfully split into {len(output_files)} files in {processing_time:.2f} seconds!")
                    
                    # Show file size distribution
                    st.write("### Generated Files:")
                    for file_info in output_files:
                        col1, col2 = st.columns([3, 1])
                        with col1:
                            status = " (compressed)" if file_info.get('compressed', False) else ""
                            st.write(f"**{file_info['filename']}** ({file_info['size_mb']:.2f} MB{status}, {file_info['pages']} pages)")
                        with col2:
                            with open(file_info['path'], 'rb') as f:
                                st.download_button(
                                    label=f"Download",
                                    data=f.read(),
                                    file_name=file_info['filename'],
                                    mime="application/pdf"
                                )
                else:
                    st.error("Error splitting the file.")
        
        # Clean up the temporary file after processing
        os.unlink(tmp_file_path)

if __name__ == "__main__":
    main()    THIS codes returns me tmpui2brstt(1).pdf (48.31 MB, 325 pages)


tmpui2brstt(2).pdf (184.57 MB(compressed), 325 pages)


tmpui2brstt(3).pdf (38.57 MB, 323 pages)  but i wnated the size of one pdf to be max 100mb ...so aftre spliiting do whatever possible but i needed 100mb not more than taht....either compress the sixze of splited pdf or other