// 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 std::path::Path;
use std::{fs, io};

use anyhow::{format_err, Context as _, Error};
use async_trait::async_trait;
use fidl_fuchsia_input_report::{
    DeviceDescriptor, InputDeviceMarker, InputDeviceProxy, InputReportsReaderMarker,
    InputReportsReaderProxy, SensorInputDescriptor, SensorType,
};

#[derive(Debug)]
pub struct AmbientLightInputRpt {
    pub illuminance: f32,
    pub red: f32,
    pub green: f32,
    pub blue: f32,
}

struct AmbientLightComponent {
    pub report_index: usize,
    pub exponent: i32,
    pub report_id: u8, // report ID associated with descriptor
}

struct AmbientLightInputReportReaderProxy {
    pub proxy: InputReportsReaderProxy,

    pub illuminance: Option<AmbientLightComponent>,
    pub red: Option<AmbientLightComponent>,
    pub green: Option<AmbientLightComponent>,
    pub blue: Option<AmbientLightComponent>,
}

fn open_input_report_device(path: &str) -> Result<InputDeviceProxy, Error> {
    tracing::info!("Opening sensor at {:?}", path);
    let (proxy, server) = fidl::endpoints::create_proxy::<InputDeviceMarker>()
        .context("Failed to create sensor proxy")?;
    fdio::service_connect(path, server.into_channel())
        .context("Failed to connect built-in service")?;
    Ok(proxy)
}

async fn open_sensor_input_report_reader() -> Result<AmbientLightInputReportReaderProxy, Error> {
    let input_report_directory = "/dev/class/input-report";
    let dir_path = Path::new(input_report_directory);
    let entries = fs::read_dir(dir_path)?;
    for entry in entries {
        let entry = entry?;
        let device_path = entry.path();
        let device_path = device_path.to_str().expect("Bad path");
        let device = open_input_report_device(device_path)?;

        fn get_sensor_input(
            descriptor: &DeviceDescriptor,
        ) -> Result<&Vec<SensorInputDescriptor>, Error> {
            let sensor = descriptor.sensor.as_ref().context("device has no sensor")?;
            let input_desc = sensor.input.as_ref().context("sensor has no input descriptor")?;
            Ok(input_desc)
        }

        if let Ok(descriptor) = device.get_descriptor().await {
            match get_sensor_input(&descriptor) {
                Ok(input_desc) => {
                    let mut illuminance = None;
                    let mut red = None;
                    let mut green = None;
                    let mut blue = None;

                    for input in input_desc {
                        match &input.values {
                            Some(axes) => {
                                for (i, val) in axes.iter().enumerate() {
                                    let component = AmbientLightComponent {
                                        report_index: i,
                                        exponent: val.axis.unit.exponent,
                                        report_id: input.report_id.unwrap_or(0),
                                    };
                                    match val.type_ {
                                        SensorType::LightIlluminance => {
                                            illuminance = Some(component)
                                        }
                                        SensorType::LightRed => red = Some(component),
                                        SensorType::LightGreen => green = Some(component),
                                        SensorType::LightBlue => blue = Some(component),
                                        _ => {}
                                    }
                                }
                            }
                            _ => {}
                        }
                    }

                    if illuminance.is_some() {
                        let (proxy, server_end) =
                            fidl::endpoints::create_proxy::<InputReportsReaderMarker>()?;
                        if let Ok(()) = device.get_input_reports_reader(server_end) {
                            return Ok(AmbientLightInputReportReaderProxy {
                                proxy: proxy,
                                illuminance,
                                red,
                                blue,
                                green,
                            });
                        }
                    }
                }
                Err(e) => {
                    tracing::info!("Skip device {}: {}", device_path, e);
                }
            };
        }
    }
    Err(io::Error::new(io::ErrorKind::NotFound, "no sensor found").into())
}

/// Reads the sensor's input report and decodes it.
async fn read_sensor_input_report(
    device: &AmbientLightInputReportReaderProxy,
) -> Result<Option<AmbientLightInputRpt>, Error> {
    let r = device.proxy.read_input_reports().await;

    match r {
        Ok(Ok(reports)) => {
            for report in reports {
                if report.report_id.unwrap_or(0) != device.illuminance.as_ref().unwrap().report_id {
                    continue;
                }

                if let Some(sensor) = report.sensor {
                    if let Some(values) = sensor.values {
                        let f = |component: &Option<AmbientLightComponent>| match component {
                            Some(val) => match val.exponent {
                                0 => values[val.report_index] as f32,
                                _ => {
                                    values[val.report_index] as f32
                                        * f32::powf(10.0, val.exponent as f32)
                                }
                            },
                            None => 0.0,
                        };

                        let illuminance = f(&device.illuminance);
                        let red = f(&device.red);
                        let green = f(&device.green);
                        let blue = f(&device.blue);

                        return Ok(Some(AmbientLightInputRpt { illuminance, red, blue, green }));
                    }
                }
            }
            Ok(None)
        }
        Ok(Err(e)) => Err(format_err!("ReadInputReports error: {}", e)),
        Err(e) => Err(format_err!("FIDL call failed: {}", e)),
    }
}

/// TODO(lingxueluo) Default and temporary report when sensor is not valid(https://fxbug.dev/42119013).
fn default_report() -> Result<Option<AmbientLightInputRpt>, Error> {
    Ok(Some(AmbientLightInputRpt { illuminance: 200.0, red: 200.0, green: 200.0, blue: 200.0 }))
}

pub struct Sensor {
    proxy: Option<AmbientLightInputReportReaderProxy>,
}

impl Sensor {
    pub async fn new() -> Sensor {
        let proxy = open_sensor_input_report_reader().await;
        match proxy {
            Ok(proxy) => return Sensor { proxy: Some(proxy) },
            Err(_e) => {
                println!("No valid sensor found.");
                return Sensor { proxy: None };
            }
        }
    }

    async fn read(&self) -> Result<Option<AmbientLightInputRpt>, Error> {
        if self.proxy.is_none() {
            default_report()
        } else {
            read_sensor_input_report(self.proxy.as_ref().unwrap()).await
        }
    }
}

#[async_trait]
pub trait SensorControl: Send {
    async fn read(&self) -> Result<Option<AmbientLightInputRpt>, Error>;
}

#[async_trait]
impl SensorControl for Sensor {
    async fn read(&self) -> Result<Option<AmbientLightInputRpt>, Error> {
        self.read().await
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use fuchsia_async as fasync;

    #[fasync::run_singlethreaded(test)]
    async fn test_open_sensor_error() {
        let sensor = Sensor { proxy: None };
        if let Some(ambient_light_input_rpt) = sensor.read().await.unwrap() {
            assert_eq!(ambient_light_input_rpt.illuminance, 200.0);
            assert_eq!(ambient_light_input_rpt.red, 200.0);
            assert_eq!(ambient_light_input_rpt.green, 200.0);
            assert_eq!(ambient_light_input_rpt.blue, 200.0);
        }
    }
}
