use anyhow::Result;
use std::sync::{Arc, atomic::AtomicBool};

use crate::nm::NMClient;
use tokio::sync::mpsc::UnboundedSender;

use ratatui::{
    Frame,
    layout::{Alignment, Constraint, Direction, Flex, Layout},
    style::{Color, Style, Stylize},
    text::{Line, Span, Text},
    widgets::{
        Block, BorderType, Borders, Clear, List, Padding, Paragraph, Row, Table, TableState,
    },
};

use crate::{
    app::FocusedBlock,
    config::Config,
    device::Device,
    event::Event,
    notification::{Notification, NotificationLevel},
};
use tui_input::Input;

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum APFocusedSection {
    SSID,
    PSK,
}

#[derive(Debug, Clone)]
pub struct AccessPoint {
    client: Arc<NMClient>,
    device_path: String,
    pub has_started: bool,
    pub name: Option<String>,
    pub frequency: Option<u32>,
    pub is_scanning: Option<bool>,
    pub supported_ciphers: Option<Vec<String>>,
    pub used_cipher: Option<String>,
    pub ap_start: Arc<AtomicBool>,
    pub ssid: Input,
    pub psk: Input,
    pub focused_section: APFocusedSection,
    pub connected_devices: Vec<String>,
    active_hotspot_path: Option<String>,
}

impl AccessPoint {
    pub async fn new(client: Arc<NMClient>, device_path: String) -> Result<Self> {
        // Check if there's an active hotspot connection
        let (has_started, name, active_hotspot_path) =
            Self::check_active_hotspot(&client, &device_path).await;

        // NetworkManager doesn't expose frequency/cipher info the same way iwd does
        // We'll populate these when the hotspot is active
        let frequency = None;
        let is_scanning = None;
        let supported_ciphers = Some(vec!["CCMP".to_string(), "TKIP".to_string()]);
        let used_cipher = Some("CCMP".to_string());
        let ap_start = Arc::new(AtomicBool::new(false));

        let ssid = Input::default();
        let psk = Input::default();
        let focused_section = APFocusedSection::SSID;

        // Connected devices would need to be queried from DHCP leases
        // This is more complex with NetworkManager
        let connected_devices = Vec::new();

        Ok(Self {
            client,
            device_path,
            has_started,
            name,
            frequency,
            is_scanning,
            supported_ciphers,
            used_cipher,
            ap_start,
            ssid,
            psk,
            focused_section,
            connected_devices,
            active_hotspot_path,
        })
    }

    #[allow(clippy::collapsible_if)]
    async fn check_active_hotspot(
        client: &NMClient,
        device_path: &str,
    ) -> (bool, Option<String>, Option<String>) {
        // Check active connections for a hotspot on this device
        if let Ok(active_connections) = client.get_active_connections().await {
            for conn_path in active_connections {
                if let Ok(info) = client.get_active_connection_info(conn_path.as_str()).await {
                    // Check if this connection is on our device and is a hotspot
                    if info.devices.contains(&device_path.to_string()) {
                        // Check if it's a hotspot by looking at the connection settings
                        if let Ok(settings) =
                            client.get_connection_settings(&info.connection_path).await
                        {
                            if let Some(wireless) = settings.get("802-11-wireless") {
                                if let Some(mode) = wireless.get("mode") {
                                    if let Ok(mode_str) =
                                        mode.try_clone().and_then(|v| v.try_into())
                                    {
                                        let mode_string: String = mode_str;
                                        if mode_string == "ap" {
                                            return (
                                                true,
                                                Some(info.id),
                                                Some(conn_path.to_string()),
                                            );
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        (false, None, None)
    }

    pub fn render_input(&self, frame: &mut Frame) {
        let popup_layout = Layout::default()
            .direction(Direction::Vertical)
            .constraints(
                [
                    Constraint::Percentage(45),
                    Constraint::Min(7),
                    Constraint::Percentage(45),
                ]
                .as_ref(),
            )
            .split(frame.area());

        let area = Layout::default()
            .direction(Direction::Horizontal)
            .constraints(
                [
                    Constraint::Length((frame.area().width - 80) / 2),
                    Constraint::Min(80),
                    Constraint::Length((frame.area().width - 80) / 2),
                ]
                .as_ref(),
            )
            .split(popup_layout[1])[1];

        let ((ssid_msg_area, ssid_input_area), (psk_msg_area, psk_input_area)) = {
            let chunks = Layout::default()
                .direction(Direction::Vertical)
                .constraints(
                    [
                        Constraint::Length(2),
                        Constraint::Length(1),
                        Constraint::Length(1),
                        Constraint::Length(1),
                        Constraint::Length(2),
                    ]
                    .as_ref(),
                )
                .split(area);

            let ssid_chunks = Layout::default()
                .direction(Direction::Horizontal)
                .constraints(
                    [
                        Constraint::Length(1),
                        Constraint::Percentage(45),
                        Constraint::Percentage(45),
                        Constraint::Length(1),
                    ]
                    .as_ref(),
                )
                .split(chunks[1]);

            let psk_chunks = Layout::default()
                .direction(Direction::Horizontal)
                .constraints(
                    [
                        Constraint::Length(1),
                        Constraint::Percentage(45),
                        Constraint::Percentage(45),
                        Constraint::Length(1),
                    ]
                    .as_ref(),
                )
                .split(chunks[3]);

            (
                (ssid_chunks[1], ssid_chunks[2]),
                (psk_chunks[1], psk_chunks[2]),
            )
        };

        let ssid_text = match self.focused_section {
            APFocusedSection::SSID => Text::from("> SSID name"),
            _ => Text::from("  SSID name"),
        };

        let psk_text = match self.focused_section {
            APFocusedSection::PSK => Text::from("> SSID password"),
            _ => Text::from("  SSID password"),
        };

        let ssid_msg = Paragraph::new(ssid_text)
            .alignment(Alignment::Left)
            .style(Style::default().fg(Color::White))
            .block(Block::new().padding(Padding::left(2)));

        let ssid_input = Paragraph::new(self.ssid.value())
            .alignment(Alignment::Center)
            .style(Style::default().fg(Color::White))
            .block(Block::new().style(Style::default().bg(Color::DarkGray)));

        let psk_msg = Paragraph::new(psk_text)
            .alignment(Alignment::Left)
            .style(Style::default().fg(Color::White))
            .block(Block::new().padding(Padding::left(2)));

        let psk_input = Paragraph::new(self.psk.value())
            .alignment(Alignment::Center)
            .style(Style::default().fg(Color::White))
            .block(Block::new().style(Style::default().bg(Color::DarkGray)));

        frame.render_widget(Clear, area);

        frame.render_widget(
            Block::new()
                .borders(Borders::ALL)
                .border_type(BorderType::Thick)
                .style(Style::default().green())
                .border_style(Style::default().fg(Color::Green)),
            area,
        );
        frame.render_widget(ssid_msg, ssid_msg_area);
        frame.render_widget(ssid_input, ssid_input_area);

        frame.render_widget(psk_msg, psk_msg_area);
        frame.render_widget(psk_input, psk_input_area);
    }

    pub async fn refresh(&mut self) -> Result<()> {
        let (has_started, name, active_hotspot_path) =
            Self::check_active_hotspot(&self.client, &self.device_path).await;

        self.has_started = has_started;
        self.name = name;
        self.active_hotspot_path = active_hotspot_path;

        // TODO: Get connected devices from DHCP leases if hotspot is active
        // This would require reading /var/lib/NetworkManager/dnsmasq-*.leases
        // or similar, which is more complex

        Ok(())
    }

    pub async fn scan(&self, sender: UnboundedSender<Event>) -> Result<()> {
        // NetworkManager doesn't support scanning in AP mode
        Notification::send(
            "Scanning not supported in AP mode".to_string(),
            NotificationLevel::Info,
            &sender,
        )?;
        Ok(())
    }

    pub async fn start(&mut self, sender: UnboundedSender<Event>) -> Result<()> {
        let ssid = self.ssid.value().to_string();
        let psk = self.psk.value().to_string();

        if ssid.is_empty() {
            Notification::send(
                "SSID cannot be empty".to_string(),
                NotificationLevel::Error,
                &sender,
            )?;
            return Ok(());
        }

        if psk.len() < 8 {
            Notification::send(
                "Password must be at least 8 characters".to_string(),
                NotificationLevel::Error,
                &sender,
            )?;
            return Ok(());
        }

        match self
            .client
            .create_hotspot(&self.device_path, &ssid, &psk)
            .await
        {
            Ok(active_path) => {
                self.has_started = true;
                self.name = Some(ssid.clone());
                self.active_hotspot_path = Some(active_path.to_string());
                Notification::send(
                    format!("AP Started\nSSID: {}", ssid),
                    NotificationLevel::Info,
                    &sender,
                )?;
            }
            Err(e) => {
                Notification::send(
                    format!("Failed to start AP: {}", e),
                    NotificationLevel::Error,
                    &sender,
                )?;
            }
        }

        self.ap_start
            .store(false, std::sync::atomic::Ordering::Relaxed);

        Ok(())
    }

    pub async fn stop(&mut self, sender: UnboundedSender<Event>) -> Result<()> {
        if let Some(active_path) = &self.active_hotspot_path {
            match self.client.deactivate_connection(active_path).await {
                Ok(()) => {
                    self.has_started = false;
                    self.name = None;
                    self.active_hotspot_path = None;
                    Notification::send("AP Stopped".to_string(), NotificationLevel::Info, &sender)?;
                }
                Err(e) => {
                    Notification::send(
                        format!("Failed to stop AP: {}", e),
                        NotificationLevel::Error,
                        &sender,
                    )?;
                }
            }
        } else {
            Notification::send(
                "No active hotspot to stop".to_string(),
                NotificationLevel::Info,
                &sender,
            )?;
        }

        Ok(())
    }

    pub fn render(
        &self,
        frame: &mut Frame,
        focused_block: FocusedBlock,
        device: &Device,
        config: Arc<Config>,
    ) {
        let (access_point_block, connected_devices_block, device_block, help_block) = {
            let chunks = Layout::default()
                .direction(Direction::Vertical)
                .constraints(if !self.connected_devices.is_empty() {
                    &[
                        Constraint::Length(5),
                        Constraint::Fill(1),
                        Constraint::Length(5),
                        Constraint::Length(1),
                    ]
                } else {
                    &[
                        Constraint::Fill(1),
                        Constraint::Length(0),
                        Constraint::Length(5),
                        Constraint::Length(1),
                    ]
                })
                .margin(1)
                .split(frame.area());
            (chunks[0], chunks[1], chunks[2], chunks[3])
        };

        // Device
        let row = Row::new(vec![
            Line::from(device.name.clone()).centered(),
            Line::from("Access Point").centered(),
            {
                if device.is_powered {
                    Line::from("On").centered()
                } else {
                    Line::from("Off").centered()
                }
            },
            Line::from(device.address.clone()).centered(),
        ]);

        let widths = [
            Constraint::Length(15),
            Constraint::Length(12),
            Constraint::Length(7),
            Constraint::Length(17),
        ];

        let device_table = Table::new(vec![row], widths)
            .header({
                if focused_block == FocusedBlock::Device {
                    Row::new(vec![
                        Line::from("Name").yellow().centered(),
                        Line::from("Mode").yellow().centered(),
                        Line::from("Powered").yellow().centered(),
                        Line::from("Address").yellow().centered(),
                    ])
                    .style(Style::new().bold())
                    .bottom_margin(1)
                } else {
                    Row::new(vec![
                        Line::from("Name").centered(),
                        Line::from("Mode").centered(),
                        Line::from("Powered").centered(),
                        Line::from("Address").centered(),
                    ])
                    .bottom_margin(1)
                }
            })
            .block(
                Block::default()
                    .title(" Device ")
                    .title_style({
                        if focused_block == FocusedBlock::Device {
                            Style::default().bold()
                        } else {
                            Style::default()
                        }
                    })
                    .borders(Borders::ALL)
                    .padding(Padding::horizontal(1))
                    .border_style({
                        if focused_block == FocusedBlock::Device {
                            Style::default().fg(Color::Green)
                        } else {
                            Style::default()
                        }
                    })
                    .border_type({
                        if focused_block == FocusedBlock::Device {
                            BorderType::Thick
                        } else {
                            BorderType::default()
                        }
                    }),
            )
            .column_spacing(2)
            .flex(Flex::SpaceAround)
            .row_highlight_style(if focused_block == FocusedBlock::Device {
                Style::default().bg(Color::DarkGray).fg(Color::White)
            } else {
                Style::default()
            });

        let mut device_state = TableState::default().with_selected(0);
        frame.render_stateful_widget(device_table, device_block, &mut device_state);

        // Access Point
        let ap_name = if self.has_started {
            self.name.as_ref().unwrap_or(&"-".to_string()).clone()
        } else {
            "-".to_string()
        };

        let ap_frequency = if self.has_started {
            if let Some(freq) = self.frequency {
                format!("{:.2} GHz", (freq / 1000))
            } else {
                "2.4 GHz".to_string() // Default for hotspot
            }
        } else {
            "-".to_string()
        };

        let ap_used_cipher = if self.has_started {
            self.used_cipher
                .as_ref()
                .unwrap_or(&"-".to_string())
                .clone()
        } else {
            "-".to_string()
        };

        let ap_is_scanning = if self.has_started {
            match self.is_scanning {
                Some(v) => v.to_string(),
                None => "-".to_string(),
            }
        } else {
            "-".to_string()
        };

        let row = Row::new(vec![
            Line::from(if self.has_started { "Yes" } else { "No" }).centered(),
            Line::from(ap_name).centered(),
            Line::from(ap_frequency).centered(),
            Line::from(ap_used_cipher).centered(),
            Line::from(ap_is_scanning).centered(),
        ]);

        let widths = [
            Constraint::Length(10),
            Constraint::Length(20),
            Constraint::Length(10),
            Constraint::Length(10),
            Constraint::Length(10),
        ];

        let access_point_table = Table::new(vec![row], widths)
            .header({
                if focused_block == FocusedBlock::AccessPoint {
                    Row::new(vec![
                        Line::from("Started").yellow().centered(),
                        Line::from("SSID").yellow().centered(),
                        Line::from("Frequency").yellow().centered(),
                        Line::from("Cipher").yellow().centered(),
                        Line::from("Scanning").yellow().centered(),
                    ])
                    .style(Style::new().bold())
                    .bottom_margin(1)
                } else {
                    Row::new(vec![
                        Line::from("Started").centered(),
                        Line::from("SSID").centered(),
                        Line::from("Frequency").centered(),
                        Line::from("Cipher").centered(),
                        Line::from("Scanning").centered(),
                    ])
                    .bottom_margin(1)
                }
            })
            .block(
                Block::default()
                    .title(" Access Point ")
                    .title_style({
                        if focused_block == FocusedBlock::AccessPoint {
                            Style::default().bold()
                        } else {
                            Style::default()
                        }
                    })
                    .borders(Borders::ALL)
                    .border_style({
                        if focused_block == FocusedBlock::AccessPoint {
                            Style::default().fg(Color::Green)
                        } else {
                            Style::default()
                        }
                    })
                    .border_type({
                        if focused_block == FocusedBlock::AccessPoint {
                            BorderType::Thick
                        } else {
                            BorderType::default()
                        }
                    })
                    .padding(Padding::horizontal(1)),
            )
            .column_spacing(2)
            .flex(Flex::SpaceAround)
            .row_highlight_style(if focused_block == FocusedBlock::AccessPoint {
                Style::default().bg(Color::DarkGray).fg(Color::White)
            } else {
                Style::default()
            });

        let mut access_point_state = TableState::default().with_selected(0);
        frame.render_stateful_widget(
            access_point_table,
            access_point_block,
            &mut access_point_state,
        );

        // Connected devices
        if !self.connected_devices.is_empty() {
            let connected_devices_list = List::new(self.connected_devices.clone()).block(
                Block::bordered()
                    .title("Connected Devices")
                    .title_style({
                        if focused_block == FocusedBlock::AccessPointConnectedDevices {
                            Style::default().bold()
                        } else {
                            Style::default()
                        }
                    })
                    .borders(Borders::ALL)
                    .border_style({
                        if focused_block == FocusedBlock::AccessPointConnectedDevices {
                            Style::default().fg(Color::Green)
                        } else {
                            Style::default()
                        }
                    })
                    .border_type({
                        if focused_block == FocusedBlock::AccessPointConnectedDevices {
                            BorderType::Thick
                        } else {
                            BorderType::default()
                        }
                    })
                    .padding(Padding::uniform(1)),
            );

            frame.render_widget(connected_devices_list, connected_devices_block);
        }

        let help_message = match focused_block {
            FocusedBlock::Device => Line::from(vec![
                Span::from(config.device.infos.to_string()).bold(),
                Span::from(" Infos"),
                Span::from(" | "),
                Span::from(config.device.toggle_power.to_string()).bold(),
                Span::from(" Toggle Power"),
                Span::from(" | "),
                Span::from("ctrl+r").bold(),
                Span::from(" Switch Mode"),
                Span::from(" | "),
                Span::from("⇄").bold(),
                Span::from(" Nav"),
            ]),
            FocusedBlock::AdapterInfos | FocusedBlock::AccessPointInput => Line::from(vec![
                Span::from("󱊷 ").bold(),
                Span::from(" Discard"),
                Span::from(" | "),
                Span::from("⇄").bold(),
                Span::from(" Nav"),
            ]),
            FocusedBlock::AccessPoint => Line::from(vec![
                Span::from(config.ap.start.to_string()).bold(),
                Span::from(" New AP"),
                Span::from(" | "),
                Span::from(config.ap.stop.to_string()).bold(),
                Span::from(" Stop AP"),
                Span::from(" | "),
                Span::from("ctrl+r").bold(),
                Span::from(" Switch Mode"),
                Span::from(" | "),
                Span::from("⇄").bold(),
                Span::from(" Nav"),
            ]),
            _ => Line::from(""),
        };

        let help_message = help_message.centered().blue();
        frame.render_widget(help_message, help_block);
    }
}
