use crate::client_db::ClientDb;
use crate::error::Result;
use crate::models::{
    AnyModel, EnvironmentIden, FolderIden, GrpcRequestIden, HttpRequestHeader, HttpRequestIden,
    ResolvedHttpRequestSettings, ResolvedSetting, WebsocketRequestIden, Workspace, WorkspaceIden,
};
use crate::util::UpdateSource;
use serde_json::Value;
use std::collections::BTreeMap;

impl<'a> ClientDb<'a> {
    pub fn get_workspace(&self, id: &str) -> Result<Workspace> {
        self.find_one(WorkspaceIden::Id, id)
    }

    pub fn list_workspaces(&self) -> Result<Vec<Workspace>> {
        let mut workspaces = self.find_all()?;

        if workspaces.is_empty() {
            workspaces.push(self.upsert_workspace(
                &Workspace {
                    name: "Yaak".to_string(),
                    setting_follow_redirects: true,
                    setting_request_message_size: crate::models::DEFAULT_REQUEST_MESSAGE_SIZE,
                    setting_validate_certificates: true,
                    ..Default::default()
                },
                &UpdateSource::Background,
            )?)
        }

        Ok(workspaces)
    }

    pub fn delete_workspace(
        &self,
        workspace: &Workspace,
        source: &UpdateSource,
    ) -> Result<Workspace> {
        for m in self.find_many(HttpRequestIden::WorkspaceId, &workspace.id, None)? {
            self.delete_http_request(&m, source)?;
        }

        for m in self.find_many(GrpcRequestIden::WorkspaceId, &workspace.id, None)? {
            self.delete_grpc_request(&m, source)?;
        }

        for m in self.find_many(WebsocketRequestIden::FolderId, &workspace.id, None)? {
            self.delete_websocket_request(&m, source)?;
        }

        for m in self.find_many(FolderIden::WorkspaceId, &workspace.id, None)? {
            self.delete_folder(&m, source)?;
        }

        for m in self.find_many(EnvironmentIden::WorkspaceId, &workspace.id, None)? {
            self.delete_environment(&m, source)?;
        }

        self.delete(workspace, source)
    }

    pub fn delete_workspace_by_id(&self, id: &str, source: &UpdateSource) -> Result<Workspace> {
        let workspace = self.get_workspace(id)?;
        self.delete_workspace(&workspace, source)
    }

    pub fn upsert_workspace(&self, w: &Workspace, source: &UpdateSource) -> Result<Workspace> {
        self.upsert(w, source)
    }

    pub fn resolve_auth_for_workspace(
        &self,
        workspace: &Workspace,
    ) -> (Option<String>, BTreeMap<String, Value>, String) {
        (
            workspace.authentication_type.clone(),
            workspace.authentication.clone(),
            workspace.id.clone(),
        )
    }

    pub fn resolve_headers_for_workspace(&self, workspace: &Workspace) -> Vec<HttpRequestHeader> {
        let mut headers = default_headers();
        headers.extend(workspace.headers.clone());
        headers
    }

    pub fn resolve_settings_for_workspace(
        &self,
        workspace: &Workspace,
    ) -> ResolvedHttpRequestSettings {
        ResolvedHttpRequestSettings {
            validate_certificates: ResolvedSetting::from_model(
                workspace.setting_validate_certificates,
                AnyModel::Workspace(workspace.clone()),
            ),
            follow_redirects: ResolvedSetting::from_model(
                workspace.setting_follow_redirects,
                AnyModel::Workspace(workspace.clone()),
            ),
            request_timeout: ResolvedSetting::from_model(
                workspace.setting_request_timeout,
                AnyModel::Workspace(workspace.clone()),
            ),
            request_message_size: ResolvedSetting::from_model(
                workspace.setting_request_message_size,
                AnyModel::Workspace(workspace.clone()),
            ),
            send_cookies: ResolvedSetting::from_model(
                workspace.setting_send_cookies,
                AnyModel::Workspace(workspace.clone()),
            ),
            store_cookies: ResolvedSetting::from_model(
                workspace.setting_store_cookies,
                AnyModel::Workspace(workspace.clone()),
            ),
        }
    }
}

/// Global default headers that are always sent with requests unless overridden.
/// These are prepended to the inheritance chain so workspace/folder/request headers
/// can override or disable them.
pub fn default_headers() -> Vec<HttpRequestHeader> {
    vec![
        HttpRequestHeader {
            enabled: true,
            name: "User-Agent".to_string(),
            value: "yaak".to_string(),
            id: None,
        },
        HttpRequestHeader {
            enabled: true,
            name: "Accept".to_string(),
            value: "*/*".to_string(),
            id: None,
        },
    ]
}
