//! Minimal groups support: insert, get, list, simple membership add/remove.
//!
//! Groups are not yet exposed over D-Bus or vCard CATEGORIES; v2 will wire
//! that up. The tables exist now so we don't need a schema migration when it
//! happens.

use rusqlite::{ Connection, OptionalExtension, params };

use crate::db::{ DbError, DbResult, now_millis };
use crate::model::group::{ Group, NewGroup };

pub fn insert( conn: &Connection, new: NewGroup ) -> DbResult<i64>
{
	let now = now_millis();
	conn.execute(
		"INSERT INTO groups( title, notes, system_id, created_at, updated_at )
		 VALUES( ?1, ?2, ?3, ?4, ?4 )",
		params![ new.title, new.notes, new.system_id, now ],
	)?;
	Ok( conn.last_insert_rowid() )
}

pub fn get( conn: &Connection, id: i64 ) -> DbResult<Group>
{
	conn.query_row(
		"SELECT _id, title, notes, system_id, deleted, created_at, updated_at
		 FROM groups WHERE _id = ?1 AND deleted = 0",
		params![ id ],
		row_to_group,
	).optional()?.ok_or( DbError::NotFound )
}

pub fn list( conn: &Connection ) -> DbResult<Vec<Group>>
{
	let mut stmt = conn.prepare(
		"SELECT _id, title, notes, system_id, deleted, created_at, updated_at
		 FROM groups WHERE deleted = 0 ORDER BY title COLLATE NOCASE"
	)?;
	let rows: Vec<Group> = stmt
		.query_map( [], row_to_group )?
		.collect::<rusqlite::Result<_>>()?;
	Ok( rows )
}

pub fn add_member( conn: &Connection, raw_contact_id: i64, group_id: i64 ) -> DbResult<()>
{
	conn.execute(
		"INSERT OR IGNORE INTO group_membership( raw_contact_id, group_id )
		 VALUES( ?1, ?2 )",
		params![ raw_contact_id, group_id ],
	)?;
	Ok( () )
}

pub fn remove_member( conn: &Connection, raw_contact_id: i64, group_id: i64 ) -> DbResult<()>
{
	conn.execute(
		"DELETE FROM group_membership
		 WHERE raw_contact_id = ?1 AND group_id = ?2",
		params![ raw_contact_id, group_id ],
	)?;
	Ok( () )
}

fn row_to_group( row: &rusqlite::Row<'_> ) -> rusqlite::Result<Group>
{
	Ok( Group {
		id:         row.get( 0 )?,
		title:      row.get( 1 )?,
		notes:      row.get( 2 )?,
		system_id:  row.get( 3 )?,
		deleted:    row.get::<_, i64>( 4 )? != 0,
		created_at: row.get( 5 )?,
		updated_at: row.get( 6 )?,
	} )
}
