use crate::database::executors::DatabaseExecutor;
use serde_json::Value;

#[cfg(test)]
use std::cell::RefCell;

#[cfg(test)]
pub struct MockState {
  pub captured_queries: Vec<String>,
  pub query_responses: Vec<Result<Value, String>>,
  pub execute_responses: Vec<Result<(), String>>,
}

#[cfg(test)]
impl MockState {
  pub fn new() -> Self {
    Self {
      captured_queries: Default::default(),
      query_responses: Default::default(),
      execute_responses: Default::default(),
    }
  }
}

#[cfg(test)]
thread_local! {
  pub static MOCK_STATE: RefCell<MockState> = RefCell::new(MockState::new());
}

#[cfg(test)]
pub struct MockExecutor {}

#[cfg(test)]
impl MockExecutor {
  pub fn new() -> Self {
    Self {}
  }
}

#[cfg(test)]
impl DatabaseExecutor for MockExecutor {
  fn query(&self, sql: &str, _args: Option<&[Value]>) -> Result<Value, String> {
    println!("DEBUG SQL QUERY: {}", sql);
    MOCK_STATE.with(|state| {
      let mut s = state.borrow_mut();
      s.captured_queries.push(sql.to_string());
      if s.query_responses.is_empty() {
        return Ok(Value::Array(vec![]));
      }
      s.query_responses.remove(0)
    })
  }

  fn execute(&self, sql: &str, _args: Option<&[Value]>) -> Result<(), String> {
    println!("DEBUG SQL EXECUTE: {}", sql);
    MOCK_STATE.with(|state| {
      let mut s = state.borrow_mut();
      s.captured_queries.push(sql.to_string());
      if s.execute_responses.is_empty() {
        return Ok(());
      }
      s.execute_responses.remove(0)
    })
  }

  fn auth_user_id(&self) -> Result<String, String> {
    Ok("00000000-0000-0000-0000-000000000000".to_string())
  }

  fn timestamp(&self) -> Result<String, String> {
    Ok("2026-03-10T00:00:00Z".to_string())
  }

  #[cfg(test)]
  fn get_queries(&self) -> Vec<String> {
    MOCK_STATE.with(|state| state.borrow().captured_queries.clone())
  }

  #[cfg(test)]
  fn reset_mocks(&self) {
    MOCK_STATE.with(|state| {
      let mut s = state.borrow_mut();
      s.captured_queries.clear();
      s.query_responses.clear();
      s.execute_responses.clear();
    });
  }
}
