// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use anyhow::{Context as _, Error};

use async_trait::async_trait;
use fidl_fuchsia_hardware_backlight::{
    DeviceMarker as BacklightMarker, DeviceProxy as BacklightProxy, State as BacklightCommand,
};
use fuchsia_syslog::fx_log_info;

const MINIMUM_BRIGHTNESS: f64 = 0.0004;

fn open_backlight() -> Result<BacklightProxy, Error> {
    fx_log_info!("Opening backlight");
    let (proxy, server) = fidl::endpoints::create_proxy::<BacklightMarker>()
        .context("Failed to create backlight proxy")?;
    // TODO(kpt): Don't hardcode this path b/138666351
    fdio::service_connect("/dev/class/backlight/000", server.into_channel())
        .context("Failed to connect built-in service")?;
    Ok(proxy)
}

pub struct Backlight {
    proxy: BacklightProxy,
}

impl Backlight {
    pub async fn new() -> Result<Backlight, Error> {
        let proxy = open_backlight()?;

        Ok(Backlight { proxy })
    }

    pub async fn get_max_absolute_brightness(&self) -> Result<f64, Error> {
        let connection_result = self.proxy.get_max_absolute_brightness().await;
        let connection = connection_result
            .map_err(|e| anyhow::format_err!("Didn't connect correctly, got err {}", e))?;
        let max_brightness: f64 = connection.map_err(|e| {
            anyhow::format_err!("Didn't get the max_brightness back, got err {}", e)
        })?;
        Ok(max_brightness)
    }

    async fn get(&self) -> Result<f64, Error> {
        let result = self.proxy.get_state_normalized().await?;
        let backlight_info =
            result.map_err(|e| anyhow::format_err!("Failed to get state: {:?}", e))?;
        assert!(backlight_info.brightness >= 0.0);
        assert!(backlight_info.brightness <= 1.0);
        Ok(if backlight_info.backlight_on { backlight_info.brightness } else { 0.0 })
    }

    fn set(&mut self, value: f64) -> Result<(), Error> {
        // TODO(fxbug.dev/36302): Handle error here as well, similar to get_brightness above. Might involve
        let regulated_value = num_traits::clamp(value, MINIMUM_BRIGHTNESS, 1.0);
        let _result = self.proxy.set_state_normalized(&mut BacklightCommand {
            backlight_on: value > 0.0,
            brightness: regulated_value,
        });
        Ok(())
    }
}

#[async_trait]
pub trait BacklightControl: Send {
    async fn get_brightness(&self) -> Result<f64, Error>;
    fn set_brightness(&mut self, value: f64) -> Result<(), Error>;
    async fn get_max_absolute_brightness(&self) -> Result<f64, Error>;
}

#[async_trait]
impl BacklightControl for Backlight {
    async fn get_brightness(&self) -> Result<f64, Error> {
        self.get().await
    }
    fn set_brightness(&mut self, value: f64) -> Result<(), Error> {
        self.set(value)
    }
    async fn get_max_absolute_brightness(&self) -> Result<f64, Error> {
        self.get_max_absolute_brightness().await
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use fidl_fuchsia_hardware_backlight::DeviceRequestStream as BacklightRequestStream;
    use fuchsia_async as fasync;
    use futures::prelude::future;
    use futures_util::stream::StreamExt;

    fn mock_backlight() -> (Backlight, BacklightRequestStream) {
        let (proxy, backlight_stream) =
            fidl::endpoints::create_proxy_and_stream::<BacklightMarker>().unwrap();
        (Backlight { proxy }, backlight_stream)
    }

    async fn mock_device_set(mut reqs: BacklightRequestStream) -> BacklightCommand {
        match reqs.next().await.unwrap() {
            Ok(fidl_fuchsia_hardware_backlight::DeviceRequest::SetStateNormalized {
                state: command,
                ..
            }) => {
                return command;
            }
            request => panic!("Unexpected request: {:?}", request),
        }
    }

    async fn mock_device_get(
        mut reqs: BacklightRequestStream,
        backlight_command: BacklightCommand,
    ) {
        match reqs.next().await.unwrap() {
            Ok(fidl_fuchsia_hardware_backlight::DeviceRequest::GetStateNormalized {
                responder,
            }) => {
                fx_log_info!("====== got GetStateNormalized");
                let response = backlight_command;
                let _ = responder.send(&mut Ok(response));
            }
            Ok(fidl_fuchsia_hardware_backlight::DeviceRequest::GetMaxAbsoluteBrightness {
                responder,
            }) => {
                fx_log_info!("====== GetMaxAbsoluteBrightness");
                if let Err(e) = responder.send(&mut Ok(250.0)) {
                    panic!("Failed to reply to GetMaxAbsoluteBrightness: {}", e);
                }
            }
            request => panic!("====== Unexpected request: {:?}", request),
        }
    }

    #[fasync::run_singlethreaded(test)]
    async fn test_brightness_returns_zero_if_screen_off() {
        // Setup
        let (mock, backlight_stream) = mock_backlight();
        let backlight_fut = mock_device_get(
            backlight_stream,
            BacklightCommand { backlight_on: false, brightness: 0.04 },
        );

        // Act
        let mock_fut = mock.get();
        let (brightness, _) = future::join(mock_fut, backlight_fut).await;

        // Assert
        assert_eq!(brightness.unwrap(), 0.0);
    }

    #[fasync::run_singlethreaded(test)]
    async fn test_brightness_returns_non_zero_if_screen_on() {
        // Setup
        let (mock, backlight_stream) = mock_backlight();
        let backlight_fut = mock_device_get(
            backlight_stream,
            BacklightCommand { backlight_on: true, brightness: 0.04 },
        );

        // Act
        let mock_fut = mock.get();
        let (brightness, _) = future::join(mock_fut, backlight_fut).await;

        // Assert
        assert_eq!(brightness.unwrap(), 0.04);
    }

    #[fasync::run_singlethreaded(test)]
    async fn test_zero_brightness_turns_screen_off() {
        // Setup
        let (mut mock, backlight_stream) = mock_backlight();
        let backlight_fut = mock_device_set(backlight_stream);

        // Act
        mock.set(0.0).expect("set failed");
        let backlight_command = backlight_fut.await;

        // Assert
        assert_eq!(backlight_command.backlight_on, false);
    }

    #[fasync::run_singlethreaded(test)]
    async fn test_negative_brightness_turns_screen_off() {
        // Setup
        let (mut mock, backlight_stream) = mock_backlight();
        let backlight_fut = mock_device_set(backlight_stream);

        // Act
        mock.set(-0.01).expect("set failed");
        let backlight_command = backlight_fut.await;

        // Assert
        assert_eq!(backlight_command.backlight_on, false);
    }

    #[fasync::run_singlethreaded(test)]
    async fn test_brightness_turns_screen_on() {
        // Setup
        let (mut mock, backlight_stream) = mock_backlight();
        let backlight_fut = mock_device_set(backlight_stream);

        // Act
        mock.set(0.55).expect("set failed");
        let backlight_command = backlight_fut.await;

        // Assert
        assert_eq!(backlight_command.backlight_on, true);
        assert_eq!(backlight_command.brightness, 0.55);
    }

    #[fasync::run_singlethreaded(test)]
    async fn test_get_max_absolute_brightness() {
        // Setup
        let (mock, backlight_stream) = mock_backlight();
        let backlight_fut = mock_device_get(
            backlight_stream,
            BacklightCommand { backlight_on: false, brightness: 0.04 },
        );

        // Act
        let mock_fut = mock.get_max_absolute_brightness();
        let (max_brightness, _) = future::join(mock_fut, backlight_fut).await;

        // Assert
        assert_eq!(max_brightness.unwrap(), 250.0);
    }
}
