//! EXIF properties panel — shows image metadata in a modal overlay.
//!
//! Replaces the v0.2 toast-based Properties action with a proper panel
//! showing dimensions, format, file size, and EXIF data (camera, lens,
//! ISO, aperture, shutter speed, timestamp, GPS) when available.

use std::path::PathBuf;

use iced::widget::{button, column, container, row, scrollable, text};
use iced::{Element, Length};

use super::icons::Icon;
use super::theme;
use crate::codec::DecodedImage;

const PANEL_WIDTH: f32 = 380.0;

#[derive(Debug, Clone, Default)]
pub struct PropertiesPanel {
    pub visible: bool,
    pub filename: String,
    pub filepath: PathBuf,
    pub width: u32,
    pub height: u32,
    pub format: String,
    pub file_size: u64,
    pub exif: Option<ExifData>,
}

#[derive(Debug, Clone, Default)]
pub struct ExifData {
    pub camera_make: Option<String>,
    pub camera_model: Option<String>,
    pub lens: Option<String>,
    pub iso: Option<u32>,
    pub aperture: Option<String>,
    pub shutter_speed: Option<String>,
    pub focal_length: Option<String>,
    pub timestamp: Option<String>,
    pub gps_lat: Option<String>,
    pub gps_lon: Option<String>,
    pub orientation: Option<u16>,
}

#[derive(Debug, Clone, Copy)]
pub enum PropertiesMessage {
    Dismiss,
}

impl PropertiesPanel {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn show(&mut self, image: &DecodedImage, path: &std::path::Path) {
        self.filename = path
            .file_name()
            .map(|s| s.to_string_lossy().to_string())
            .unwrap_or_default();
        self.filepath = path.to_path_buf();
        self.width = image.width;
        self.height = image.height;
        self.format = image.format.to_string();
        self.file_size = std::fs::metadata(path).map(|m| m.len()).unwrap_or(0);
        self.exif = parse_exif(path);
        self.visible = true;
    }

    pub fn dismiss(&mut self) {
        self.visible = false;
    }

    pub fn view(&self) -> Option<Element<'_, PropertiesMessage>> {
        if !self.visible {
            return None;
        }

        let close_btn = button(
            row![
                Icon::Close.widget(14.0, &theme::text_primary_hex()),
                text("Close").color(theme::TEXT_PRIMARY).size(12),
            ]
            .align_y(iced::Alignment::Center)
            .spacing(6.0),
        )
        .on_press(PropertiesMessage::Dismiss)
        .padding(iced::Padding {
            top: 5.0,
            right: 14.0,
            bottom: 5.0,
            left: 14.0,
        })
        .style(|_theme, status| {
            let bg = match status {
                button::Status::Hovered => Some(theme::BG_CHROME_HOVER),
                _ => None,
            };
            button::Style {
                background: bg.map(iced::Background::Color),
                border: iced::Border {
                    color: theme::BG_CHROME_BORDER,
                    width: 1.0,
                    radius: 4.0.into(),
                },
                ..Default::default()
            }
        });

        let header = row![
            Icon::Info.widget(18.0, &theme::text_secondary_hex()),
            text("Properties").color(theme::TEXT_PRIMARY).size(16),
            text("").width(Length::Fill),
            close_btn,
        ]
        .align_y(iced::Alignment::Center)
        .spacing(8.0);

        let filename_text = text(self.filename.clone())
            .color(theme::TEXT_PRIMARY)
            .size(14);

        let label = |s: &'static str| {
            text(s)
                .color(theme::TEXT_SECONDARY)
                .size(11)
                .width(Length::Fixed(100.0))
        };
        let value = |s: String| {
            text(s)
                .color(theme::TEXT_PRIMARY)
                .size(11)
        };

        let size_str = format_file_size(self.file_size);
        let dims_str = format!("{} × {}", self.width, self.height);

        let info_rows = vec![
            row![label("Path:"), value(self.filepath.display().to_string())].spacing(4.0),
            row![label("Dimensions:"), value(dims_str)].spacing(4.0),
            row![label("Format:"), value(self.format.clone())].spacing(4.0),
            row![label("File size:"), value(size_str)].spacing(4.0),
        ];

        let mut all_rows: Vec<Element<'_, PropertiesMessage>> = vec![
            header.into(),
            text("").height(Length::Fixed(8.0)).into(),
            filename_text.into(),
            text("").height(Length::Fixed(12.0)).into(),
        ];

        // Info section
        for r in info_rows {
            all_rows.push(r.into());
        }

        // EXIF section (if available)
        if let Some(exif) = &self.exif {
            all_rows.push(text("").height(Length::Fixed(16.0)).into());

            let exif_title = text("EXIF Metadata")
                .color(theme::ACCENT)
                .size(12);
            all_rows.push(exif_title.into());
            all_rows.push(text("").height(Length::Fixed(8.0)).into());

            let exif_rows = build_exif_rows(exif, &label, &value);
            for r in exif_rows {
                all_rows.push(r.into());
            }
        }

        let content = column(all_rows)
            .padding(iced::Padding {
                top: 20.0,
                right: 20.0,
                bottom: 20.0,
                left: 20.0,
            })
            .spacing(4.0);

        let scrollable_content = scrollable(content)
            .direction(scrollable::Direction::Vertical(
                scrollable::Scrollbar::new().width(4).scroller_width(4),
            ))
            .width(Length::Fill)
            .height(Length::Fill);

        let card = container(scrollable_content)
            .max_width(PANEL_WIDTH)
            .max_height(500.0)
            .style(|_| container::Style {
                background: Some(theme::BG_CHROME.into()),
                border: iced::Border {
                    color: theme::BG_CHROME_BORDER,
                    width: 1.0,
                    radius: 8.0.into(),
                },
                shadow: iced::Shadow {
                    color: iced::Color::from_rgba(0.0, 0.0, 0.0, 0.7),
                    offset: iced::Vector::new(0.0, 8.0),
                    blur_radius: 32.0,
                },
                ..Default::default()
            });

        let centered = container(card)
            .width(Length::Fill)
            .height(Length::Fill)
            .align_x(iced::Alignment::Center)
            .align_y(iced::Alignment::Center)
            .style(|_| container::Style {
                background: Some(
                    iced::Color::from_rgba(0.0, 0.0, 0.0, 0.75).into(),
                ),
                ..Default::default()
            });

        Some(centered.into())
    }
}

fn build_exif_rows(
    exif: &ExifData,
    label: &impl Fn(&'static str) -> iced::widget::Text<'static>,
    value: &impl Fn(String) -> iced::widget::Text<'static>,
) -> Vec<iced::widget::Row<'static, PropertiesMessage>> {
    let mut rows = Vec::new();

    if let Some(make) = &exif.camera_make {
        rows.push(row![label("Make:"), value(make.clone())].spacing(4.0));
    }
    if let Some(model) = &exif.camera_model {
        rows.push(row![label("Model:"), value(model.clone())].spacing(4.0));
    }
    if let Some(lens) = &exif.lens {
        rows.push(row![label("Lens:"), value(lens.clone())].spacing(4.0));
    }
    if let Some(iso) = exif.iso {
        rows.push(row![label("ISO:"), value(format!("{}", iso))].spacing(4.0));
    }
    if let Some(aperture) = &exif.aperture {
        rows.push(row![label("Aperture:"), value(aperture.clone())].spacing(4.0));
    }
    if let Some(shutter) = &exif.shutter_speed {
        rows.push(row![label("Shutter:"), value(shutter.clone())].spacing(4.0));
    }
    if let Some(focal) = &exif.focal_length {
        rows.push(row![label("Focal:"), value(focal.clone())].spacing(4.0));
    }
    if let Some(ts) = &exif.timestamp {
        rows.push(row![label("Date:"), value(ts.clone())].spacing(4.0));
    }
    if let Some(lat) = &exif.gps_lat {
        rows.push(row![label("GPS Lat:"), value(lat.clone())].spacing(4.0));
    }
    if let Some(lon) = &exif.gps_lon {
        rows.push(row![label("GPS Lon:"), value(lon.clone())].spacing(4.0));
    }
    if let Some(orient) = exif.orientation {
        rows.push(row![label("Orientation:"), value(format!("{}", orient))].spacing(4.0));
    }

    rows
}

fn format_file_size(bytes: u64) -> String {
    if bytes >= 1_000_000_000 {
        format!("{:.2} GB", bytes as f64 / 1_000_000_000.0)
    } else if bytes >= 1_000_000 {
        format!("{:.1} MB", bytes as f64 / 1_000_000.0)
    } else if bytes >= 1_000 {
        format!("{:.1} KB", bytes as f64 / 1_000.0)
    } else {
        format!("{} B", bytes)
    }
}

/// Parse EXIF data from a file using kamadak-exif.
fn parse_exif(path: &std::path::Path) -> Option<ExifData> {
    let file = std::fs::File::open(path).ok()?;
    let mut bufreader = std::io::BufReader::new(&file);
    let exif_reader = exif::Reader::new();
    let exif = exif_reader.read_from_container(&mut bufreader).ok()?;

    let mut data = ExifData::default();

    for field in exif.fields() {
        let tag = field.tag;
        let value_str = field.display_value().with_unit(&exif).to_string();

        match tag {
            exif::Tag::Make => {
                data.camera_make = Some(value_str.trim().to_string());
            }
            exif::Tag::Model => {
                data.camera_model = Some(value_str.trim().to_string());
            }
            exif::Tag::LensModel => {
                data.lens = Some(value_str.trim().to_string());
            }
            exif::Tag::PhotographicSensitivity => {
                data.iso = value_str.trim().parse().ok();
            }
            exif::Tag::FNumber => {
                data.aperture = Some(format!("f/{}", value_str.trim()));
            }
            exif::Tag::ExposureTime => {
                data.shutter_speed = Some(value_str.trim().to_string());
            }
            exif::Tag::FocalLength => {
                data.focal_length = Some(value_str.trim().to_string());
            }
            exif::Tag::DateTimeOriginal | exif::Tag::DateTime => {
                data.timestamp = Some(value_str.trim().to_string());
            }
            exif::Tag::GPSLatitude => {
                data.gps_lat = Some(value_str.trim().to_string());
            }
            exif::Tag::GPSLongitude => {
                data.gps_lon = Some(value_str.trim().to_string());
            }
            exif::Tag::Orientation => {
                data.orientation = value_str.trim().parse().ok();
            }
            _ => {}
        }
    }

    if data.camera_make.is_none()
        && data.camera_model.is_none()
        && data.iso.is_none()
        && data.timestamp.is_none()
    {
        return None;
    }

    Some(data)
}
