// Copyright 2020 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 {
    crate::{
        descriptor::EventDescriptor,
        events::{event_name, EventSource, EventStream},
        matcher::EventMatcher,
    },
    anyhow::{format_err, Error},
    fuchsia_async as fasync,
    futures::{channel::oneshot, future::BoxFuture},
    std::convert::TryFrom,
};

/// Ordering is used by `EventSequence::subscribe_and_expect`to determine if it should allow events to be
/// verified in any order or only in the order specified by the test.
#[derive(Clone)]
pub enum Ordering {
    Ordered,
    Unordered,
}

#[derive(Clone)]
pub struct EventSequence {
    groups: Vec<EventGroup>,
}

impl EventSequence {
    pub fn new() -> Self {
        Self { groups: vec![] }
    }

    pub fn then(self, matcher: EventMatcher) -> Self {
        self.all_of(vec![matcher], Ordering::Ordered)
    }

    pub fn all_of(mut self, events: Vec<EventMatcher>, ordering: Ordering) -> Self {
        self.groups.push(EventGroup::new(events, ordering));
        self
    }

    /// Verify that the events in this sequence are received from the provided
    /// EventStream.
    pub async fn expect(mut self, mut event_stream: EventStream) -> Result<(), Error> {
        while !self.groups.is_empty() {
            match event_stream.next().await {
                Err(e) => return Err(e.into()),
                Ok(event) => {
                    let actual_event = EventDescriptor::try_from(&event)?;
                    if actual_event.target_moniker != Some(".".to_string()) {
                        let _ = self.next(&actual_event)?;
                    }
                }
            }
        }
        Ok(())
    }

    /// Verifies that the given events are received from the event system. Based on the vector of
    /// events passed in this function will subscribe to an event stream with the relevant event
    /// types and verify that the correct events for the component are received.
    pub async fn subscribe_and_expect<'a>(
        self,
        event_source: &mut EventSource,
    ) -> Result<BoxFuture<'a, Result<(), Error>>, Error> {
        let event_names = self.event_names()?;
        let event_stream = event_source.subscribe(event_names).await?;
        let expected_events = self.clone();
        let (tx, rx) = oneshot::channel();
        fasync::Task::spawn(async move {
            let res = expected_events.expect(event_stream).await;
            tx.send(res).expect("Unable to send result");
        })
        .detach();

        Ok(Box::pin(async move { rx.await? }))
    }

    pub fn is_empty(&self) -> bool {
        self.groups.is_empty()
    }

    pub fn event_names(&self) -> Result<Vec<String>, Error> {
        let mut event_names = vec![];
        for group in &self.groups {
            let mut group_event_names = group.event_names()?;
            event_names.append(&mut group_event_names);
        }
        event_names.dedup();
        Ok(event_names)
    }

    // Takes in an EventDescriptor and tests it against the first EventGroup.
    // If an EventGroup has been entirely consumed (no further EventMatchers
    // to match against) then the EventGroup is dropped. If the
    // EventSequence have not been entirely consumed, and the incoming
    // EventDescriptor does not match the first sequence then an error is returned.
    // If the EventSequence is empty, then Ok(false) is returned. Otherwise, if
    // there is a positive match, then Ok(true) is returned.
    pub fn next(&mut self, event: &EventDescriptor) -> Result<(), Error> {
        loop {
            if self.groups.is_empty() {
                return Ok(());
            }
            let group = &mut self.groups[0];
            if group.next(event)? {
                if group.is_empty() {
                    self.groups.remove(0);
                }
                return Ok(());
            }
            self.groups.remove(0);
        }
    }
}

#[derive(Clone)]
pub struct EventGroup {
    events: Vec<EventMatcher>,
    ordering: Ordering,
}

impl EventGroup {
    pub fn new(events: Vec<EventMatcher>, ordering: Ordering) -> Self {
        Self { events, ordering }
    }

    pub fn is_empty(&self) -> bool {
        self.events.is_empty()
    }

    pub fn event_names(&self) -> Result<Vec<String>, Error> {
        let mut event_names = vec![];
        for event in &self.events {
            if let Some(event_type) = &event.event_type {
                event_names.push(event_name(&event_type.value()));
            } else {
                return Err(format_err!("No event name or type set for matcher {:?}", event));
            }
        }
        event_names.dedup();
        Ok(event_names)
    }

    // Takes in an EventDescriptor and tests it against the next EventMatcher in
    // the sequence. If the sequence is empty, then Ok(false) is returned. If
    // the sequence is Ordered, then this tests it against the first
    // EventMatcher. If the sequence is Unordered, then this tests the
    // EventDescriptor against all EventMatchers in the sequence to find a
    // match. In either case, if no match is found, then an Error is returned.
    // If there is a positive match, then Ok(true) is returned.
    pub fn next(&mut self, event: &EventDescriptor) -> Result<bool, Error> {
        if self.events.is_empty() {
            return Ok(false);
        }
        let expected_event = match self.ordering {
            Ordering::Ordered => self.events.remove(0),
            Ordering::Unordered => {
                if let Some((index, _)) = self
                    .events
                    .iter()
                    .enumerate()
                    .find(|&matcher| matcher.1.matches(&event).is_ok())
                {
                    self.events.remove(index)
                } else {
                    return Err(format_err!("Failed to find event: {:?}", event));
                }
            }
        };
        expected_event.matches(&event).map(|_| true).map_err(|e| format_err!("{}", e))
    }
}
