using System;
using System.IO;
using System.Text;

namespace Base64PdfValidator
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("=== Base64 PDF Validator and Converter ===");
            Console.WriteLine("This program validates if a base64 string represents a valid PDF file and converts it to PDF.");
            Console.WriteLine();

            while (true)
            {
                Console.Write("Enter base64 encoded PDF string (or 'exit' to quit): ");
                string input = Console.ReadLine();

                if (string.IsNullOrWhiteSpace(input) || input.Equals("exit", StringComparison.OrdinalIgnoreCase))
                {
                    break;
                }

                try
                {
                    // Trim any whitespace or potential data URL prefix
                    string base64Data = input.Trim();
                    if (base64Data.StartsWith("data:"))
                    {
                        // Extract base64 data from data URL
                        int base64Index = base64Data.IndexOf(",");
                        if (base64Index > 0)
                        {
                            base64Data = base64Data.Substring(base64Index + 1);
                        }
                    }

                    // Validate base64 format
                    if (!IsValidBase64(base64Data))
                    {
                        Console.WriteLine("❌ Invalid base64 format.");
                        continue;
                    }

                    // Decode base64 to bytes
                    byte[] pdfBytes = Convert.FromBase64String(base64Data);
                    Console.WriteLine($"✅ Successfully decoded base64 to {pdfBytes.Length} bytes.");

                    // Validate if it's a PDF
                    if (IsValidPdf(pdfBytes))
                    {
                        Console.WriteLine("✅ Valid PDF file format detected.");

                        // Save as PDF
                        string fileName = $"output_{DateTime.Now:yyyyMMdd_HHmmss}.pdf";
                        File.WriteAllBytes(fileName, pdfBytes);
                        Console.WriteLine($"✅ PDF file saved as: {fileName}");
                    }
                    else
                    {
                        Console.WriteLine("❌ Not a valid PDF file.");
                        
                        // Try to detect file type from header
                        string detectedType = DetectFileType(pdfBytes);
                        if (!string.IsNullOrEmpty(detectedType))
                        {
                            Console.WriteLine($"📄 Detected file type: {detectedType}");
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"❌ Error: {ex.Message}");
                    Console.WriteLine($"📋 Stack trace: {ex.StackTrace}");
                }
                finally
                {
                    Console.WriteLine();
                }
            }

            Console.WriteLine("Program exited.");
        }

        /// <summary>
        /// Validates if a string is valid base64
        /// </summary>
        private static bool IsValidBase64(string base64)
        {
            try
            {
                Convert.FromBase64String(base64);
                return true;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Validates if bytes represent a valid PDF file
        /// </summary>
        private static bool IsValidPdf(byte[] bytes)
        {
            if (bytes == null || bytes.Length < 4)
            {
                return false;
            }

            // PDF files start with "%PDF-"
            byte[] pdfHeader = Encoding.ASCII.GetBytes("%PDF-");
            for (int i = 0; i < pdfHeader.Length; i++)
            {
                if (bytes[i] != pdfHeader[i])
                {
                    return false;
                }
            }

            // Optional: Check for "%%EOF" at the end (more reliable)
            if (bytes.Length > 5)
            {
                byte[] pdfFooter = Encoding.ASCII.GetBytes("%%EOF");
                int footerIndex = bytes.Length - pdfFooter.Length;
                
                // Check if footer exists at the end
                bool hasFooter = true;
                for (int i = 0; i < pdfFooter.Length; i++)
                {
                    if (bytes[footerIndex + i] != pdfFooter[i])
                    {
                        hasFooter = false;
                        break;
                    }
                }

                // For more robust validation, we could check for "%%EOF" anywhere in the last 100 bytes
                if (!hasFooter)
                {
                    // Search for "%%EOF" in the last 100 bytes
                    int searchStart = Math.Max(0, bytes.Length - 100);
                    string lastPart = Encoding.ASCII.GetString(bytes, searchStart, bytes.Length - searchStart);
                    return lastPart.Contains("%%EOF");
                }
            }

            return true;
        }

        /// <summary>
        /// Tries to detect the file type from its header bytes
        /// </summary>
        private static string DetectFileType(byte[] bytes)
        {
            if (bytes == null || bytes.Length < 4)
            {
                return "Unknown";
            }

            // Check common file signatures (magic numbers)
            if (bytes[0] == 0x25 && bytes[1] == 0x50 && bytes[2] == 0x44 && bytes[3] == 0x46) // %PDF
            {
                return "PDF";
            }
            else if (bytes[0] == 0xFF && bytes[1] == 0xD8) // JPEG
            {
                return "JPEG/JPG";
            }
            else if (bytes[0] == 0x89 && bytes[1] == 0x50 && bytes[2] == 0x4E && bytes[3] == 0x47) // PNG
            {
                return "PNG";
            }
            else if (bytes[0] == 0x47 && bytes[1] == 0x49 && bytes[2] == 0x46) // GIF
            {
                return "GIF";
            }
            else if (bytes[0] == 0x50 && bytes[1] == 0x4B && bytes[2] == 0x03 && bytes[3] == 0x04) // ZIP
            {
                return "ZIP/Office Document";
            }
            else if (bytes[0] == 0x00 && bytes[1] == 0x00 && bytes[2] == 0x01 && bytes[3] == 0xBA) // MP4
            {
                return "MP4";
            }
            else if (bytes[0] == 0x42 && bytes[1] == 0x4D) // BMP
            {
                return "BMP";
            }

            return "Unknown file type";
        }
    }
}
