# Copyright (c) DevSecCode. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root.

"""REST endpoints for credential vault management.

NOTE: The master password is accepted via request body for now.
In production, it should be provided via IPC only (never HTTP over a
network).  Since the backend binds to 127.0.0.1, this is acceptable
for local development.
"""

from __future__ import annotations

import logging
from typing import Any

from fastapi import APIRouter, HTTPException, Query
from pydantic import BaseModel

from dsc_api.services.credential_vault import CredentialVault, VaultError

logger = logging.getLogger(__name__)
router = APIRouter()

# Per-workspace vault cache (workspace_path → CredentialVault)
_vaults: dict[str, CredentialVault] = {}


def _get_vault(workspace: str) -> CredentialVault:
	if workspace not in _vaults:
		_vaults[workspace] = CredentialVault(workspace)
	return _vaults[workspace]


class UnlockRequest(BaseModel):
	master_password: str


class StoreCredentialRequest(BaseModel):
	credential_id: str
	credentials: dict[str, str]
	master_password: str


class DeleteCredentialRequest(BaseModel):
	master_password: str


@router.post("/unlock")
async def unlock_vault(
	body: UnlockRequest,
	workspace: str = Query(..., description="Absolute workspace path"),
) -> dict[str, Any]:
	"""Unlock the credential vault with the master password."""
	vault = _get_vault(workspace)
	try:
		vault.unlock(body.master_password)
		return {'status': 'unlocked', 'credential_count': len(vault.list_ids())}
	except VaultError as exc:
		raise HTTPException(status_code=403, detail=str(exc))


@router.post("/lock")
async def lock_vault(
	workspace: str = Query(..., description="Absolute workspace path"),
) -> dict[str, Any]:
	"""Lock the credential vault, wiping in-memory keys."""
	vault = _get_vault(workspace)
	vault.lock()
	return {'status': 'locked'}


@router.get("")
async def list_credentials(
	workspace: str = Query(..., description="Absolute workspace path"),
) -> dict[str, Any]:
	"""List stored credential IDs (metadata only — no secrets)."""
	vault = _get_vault(workspace)
	if not vault.is_unlocked:
		return {'unlocked': False, 'credentials': []}
	return {
		'unlocked': True,
		'credentials': [{'id': cid} for cid in vault.list_ids()],
	}


@router.post("")
async def store_credential(
	body: StoreCredentialRequest,
	workspace: str = Query(..., description="Absolute workspace path"),
) -> dict[str, Any]:
	"""Store or update a credential set."""
	vault = _get_vault(workspace)
	try:
		if not vault.is_unlocked:
			vault.unlock(body.master_password)
		vault.store(body.credential_id, body.credentials, body.master_password)
		return {'status': 'stored', 'credential_id': body.credential_id}
	except VaultError as exc:
		raise HTTPException(status_code=400, detail=str(exc))


@router.delete("/{credential_id}")
async def delete_credential(
	credential_id: str,
	body: DeleteCredentialRequest,
	workspace: str = Query(..., description="Absolute workspace path"),
) -> dict[str, Any]:
	"""Delete a credential set."""
	vault = _get_vault(workspace)
	try:
		if not vault.is_unlocked:
			vault.unlock(body.master_password)
		deleted = vault.delete(credential_id, body.master_password)
		if not deleted:
			raise HTTPException(status_code=404, detail=f"Credential not found: {credential_id}")
		return {'status': 'deleted', 'credential_id': credential_id}
	except VaultError as exc:
		raise HTTPException(status_code=400, detail=str(exc))
