mod html_parser;
mod pdf_generator;
mod template_renderer;

use anyhow::{anyhow, Result};
use base64::prelude::*;
use bulletin_shared::{Config, NewApiClient};
use chrono::{Datelike, Local, NaiveDate, Weekday};
use clap::Parser;
use std::path::PathBuf;

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
    #[arg(short, long, default_value = "shared/config.toml")]
    config: PathBuf,
    
    #[arg(short, long)]
    date: Option<NaiveDate>,
    
    #[arg(short, long, default_value = "output")]
    output_dir: PathBuf,
    
    #[arg(long)]
    no_upload: bool,
}

fn get_upcoming_saturday(from_date: Option<NaiveDate>) -> NaiveDate {
    let today = from_date.unwrap_or_else(|| Local::now().date_naive());
    
    if today.weekday() == Weekday::Sat && from_date.is_none() {
        return today;
    }
    
    let days_until_saturday = match today.weekday() {
        Weekday::Sat => 7,
        Weekday::Sun => 6,
        Weekday::Mon => 5,
        Weekday::Tue => 4,
        Weekday::Wed => 3,
        Weekday::Thu => 2,
        Weekday::Fri => 1,
    };
    
    today + chrono::Duration::days(days_until_saturday as i64)
}

#[tokio::main]
async fn main() -> Result<()> {
    // Load environment variables from .env file
    dotenvy::dotenv().ok();
    
    tracing_subscriber::fmt()
        .with_env_filter("info")
        .init();

    let args = Args::parse();
    
    let config = Config::from_file(&args.config)?;
    
    let target_date = args.date.unwrap_or_else(|| get_upcoming_saturday(None));
    
    println!("--- Starting bulletin generation process for date: {} ---", target_date);
    
    let client = NewApiClient::new();
    
    println!("Fetching current bulletin data from new API...");
    let new_bulletin = client.get_current_bulletin().await?;
    let bulletin = bulletin_shared::new_api::convert_to_bulletin(new_bulletin.clone())?;
    
    let _bulletin_id = bulletin.id.as_ref()
        .ok_or_else(|| anyhow!("Bulletin record ID missing"))?;
    
    println!("Downloading cover image...");
    let cover_image_path = if let Some(ref cover_image) = bulletin.cover_image {
        let temp_dir = std::env::temp_dir().join("bulletin_images");
        std::fs::create_dir_all(&temp_dir)?;
        
        // Handle both full URLs and relative paths
        let image_url = if cover_image.starts_with("http") {
            cover_image.clone()
        } else {
            format!("https://api.rockvilletollandsda.church/uploads/bulletins/{}", cover_image)
        };
        let response = reqwest::get(&image_url).await?;
        
        if response.status().is_success() {
            let image_data = response.bytes().await?;
            // Extract filename from URL if it's a full URL, otherwise use as-is
            let filename = if cover_image.starts_with("http") {
                cover_image.split('/').last().unwrap_or("cover_image.webp")
            } else {
                cover_image
            };
            let image_path = temp_dir.join(filename);
            std::fs::write(&image_path, &image_data)?;
            
            // Convert to base64 data URL for PDF rendering
            let mime_type = if filename.ends_with(".webp") {
                "image/webp"
            } else if filename.ends_with(".jpg") || filename.ends_with(".jpeg") {
                "image/jpeg"
            } else if filename.ends_with(".png") {
                "image/png"
            } else {
                "image/webp" // default
            };
            let base64_data = base64::prelude::BASE64_STANDARD.encode(&image_data);
            let data_url = format!("data:{};base64,{}", mime_type, base64_data);
            
            Some(std::path::PathBuf::from(data_url))
        } else {
            println!("Failed to download cover image: HTTP {} from {}", response.status(), image_url);
            None
        }
    } else {
        println!("No cover image found, continuing without it");
        None
    };
    
    println!("Fetching upcoming events...");
    let events = client.get_upcoming_events_as_events().await.unwrap_or_else(|e| {
        eprintln!("Failed to fetch events: {}", e);
        Vec::new()
    });
    
    println!("Parsing Sabbath School text...");
    let sabbath_school_items = html_parser::parse_sabbath_school(&bulletin.sabbath_school_section);
    
    println!("Parsing Divine Worship text...");
    let divine_worship_items = html_parser::parse_divine_worship(&bulletin.divine_worship_section);
    
    println!("Grouping similar events...");
    let announcements = template_renderer::group_similar_events(events);
    println!("Grouped events into {} announcement items", announcements.len());

    println!("Preparing template context...");
    let context = template_renderer::TemplateContext {
        bulletin_date: target_date.format("%B %d, %Y").to_string(),
        bulletin_theme_title: html_parser::strip_html_tags(&bulletin.sermon_title),
        church_name: config.church_name.clone(),
        cover_image_path: cover_image_path.as_ref().map(|p| p.to_string_lossy().to_string()),
        sabbath_school_items,
        divine_worship_items,
        announcements,
        sunset_times: new_bulletin.sunset.unwrap_or_else(|| "TBA".to_string()),
        contact_info: template_renderer::ContactInfo {
            phone: config.contact_phone.clone().unwrap_or_else(|| "860-875-0450".to_string()),
            website: config.contact_website.clone().unwrap_or_else(|| "rockvilletollandsda.church".to_string()),
            address: config.contact_address.clone().unwrap_or_else(|| "9 Hartford Tpke Tolland CT 06084".to_string()),
        },
    };
    
    println!("Rendering HTML template...");
    let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let template_dir = manifest_dir.join("templates");
    let html_content = template_renderer::render_template(&template_dir, &context)?;
    
    println!("Generating PDF...");
    std::fs::create_dir_all(&args.output_dir)?;
    let pdf_filename = format!("bulletin_{}.pdf", target_date.format("%Y-%m-%d"));
    let pdf_path = args.output_dir.join(&pdf_filename);
    
    pdf_generator::generate_pdf(&html_content, &template_dir, &pdf_path)?;
    
    if !args.no_upload {
        println!("Uploading PDF to API...");
        
        // Try to get auth token from environment, or login with credentials
        let client_with_auth = if let Ok(auth_token) = std::env::var("BULLETIN_API_TOKEN") {
            NewApiClient::new().with_auth_token(auth_token)
        } else if let (Ok(username), Ok(password)) = (std::env::var("BULLETIN_API_USERNAME"), std::env::var("BULLETIN_API_PASSWORD")) {
            println!("Logging in with credentials...");
            match NewApiClient::new().login(username, password).await {
                Ok(client) => client,
                Err(e) => {
                    eprintln!("Failed to login: {}", e);
                    println!("PDF is available locally at: {}", pdf_path.display());
                    return Ok(());
                }
            }
        } else {
            println!("No BULLETIN_API_TOKEN or credentials found in environment - PDF saved locally only");
            println!("Add BULLETIN_API_TOKEN or BULLETIN_API_USERNAME/BULLETIN_API_PASSWORD to .env file to enable PDF upload");
            return Ok(());
        };
        
        println!("Uploading PDF for bulletin ID: {}", _bulletin_id);
        match client_with_auth.upload_pdf(_bulletin_id, &pdf_path).await {
            Ok(_) => println!("Successfully uploaded PDF to API"),
            Err(e) => {
                eprintln!("Failed to upload PDF to API: {}", e);
                println!("PDF is available locally at: {}", pdf_path.display());
            }
        }
    }
    
    if let Some(ref image_path) = cover_image_path {
        let _ = std::fs::remove_file(image_path);
    }
    
    println!("--- Bulletin generation process for date: {} COMPLETED ---", target_date);
    println!("PDF saved to: {}", pdf_path.display());
    
    Ok(())
}