# BuyMetric API v1

Base URL: `http://localhost:8000/api/v1`

All requests should send `Accept: application/json`. Protected endpoints also require `Authorization: Bearer TOKEN`.

## Register

`POST /register` — public. Send `name`, `email`, `password`, and `password_confirmation`. A successful request returns **201** with `success`, a user (`id`, `name`, `email`, `created_at`), and a plaintext personal access token. Invalid input or a duplicate email returns **422** with `success: false`, `message: "Validation failed."`, and `errors`.

```bash
curl -X POST http://localhost:8000/api/v1/register \
  -H "Accept: application/json" -H "Content-Type: application/json" \
  -d '{"name":"Juan Dela Cruz","email":"juan@example.com","password":"password123","password_confirmation":"password123"}'
```

## Login

`POST /login` — public. Send `email` and `password`. A successful request returns **200** with the public user fields and a newly created token. Invalid input returns **422**; invalid credentials return **401** with `Invalid email or password.`

```bash
curl -X POST http://localhost:8000/api/v1/login \
  -H "Accept: application/json" -H "Content-Type: application/json" \
  -d '{"email":"juan@example.com","password":"password123"}'
```

## Current user

`GET /me` — requires a bearer token. Returns **200** with `id`, `name`, `email`, `currency`, `monthly_income`, `monthly_discretionary_budget`, and `created_at`. Monetary values are strings with two decimal places to preserve decimal precision; unset financial values are `null`. A missing or invalid token returns **401** with a JSON unauthenticated error.

```bash
curl http://localhost:8000/api/v1/me \
  -H "Accept: application/json" -H "Authorization: Bearer YOUR_TOKEN"
```

## Update profile

`PATCH /profile` — requires a bearer token. All fields are optional: `name`, `currency`, `monthly_income`, and `monthly_discretionary_budget`. Supported currencies are `PHP`, `USD`, `AUD`, `EUR`, `GBP`, `SGD`, and `JPY`; currency input is normalized to uppercase. The financial fields accept non-negative values with up to two decimal places, or `null` to clear a value. Invalid fields return **422** with the standard validation error format.

```bash
curl -X PATCH http://localhost:8000/api/v1/profile \
  -H "Accept: application/json" -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"name":"Juan Dela Cruz","currency":"PHP","monthly_income":50000,"monthly_discretionary_budget":10000}'
```

Update only income:

```bash
curl -X PATCH http://localhost:8000/api/v1/profile \
  -H "Accept: application/json" -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"monthly_income":55000}'
```

Clear income:

```bash
curl -X PATCH http://localhost:8000/api/v1/profile \
  -H "Accept: application/json" -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"monthly_income":null}'
```

## Items

All item endpoints require `Authorization: Bearer TOKEN`. Items belong to the authenticated user and never expose `user_id`. Another user's item returns **404**.

### Create an item

`POST /items` accepts `name`, `category`, `price`, and an optional `currency`. Names are trimmed, categories are normalized to lowercase, and currency is normalized to uppercase. When omitted, currency defaults to the authenticated user's profile currency. Price must be greater than zero and have no more than two decimal places. New items always start with `status: "evaluating"`; client-supplied ownership and status are ignored.

```bash
curl -X POST http://localhost:8000/api/v1/items \
  -H "Accept: application/json" -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"name":"AirPods Pro","category":"electronics","price":14990,"currency":"PHP"}'
```

### List items

`GET /items` returns only the authenticated user's items, newest first. Results are paginated at 15 items by default; `per_page` accepts 1–50. Optional filters can be combined: `status` (`evaluating`, `waiting`, `purchased`, or `skipped`), exact `category`, and case-insensitive `search` over names. Invalid query values return **422**.

```bash
curl "http://localhost:8000/api/v1/items?status=evaluating&category=electronics" \
  -H "Accept: application/json" -H "Authorization: Bearer YOUR_TOKEN"
```

### Retrieve one item

`GET /items/{item}` returns an owned item, or **404** when it is not owned by the caller.

```bash
curl http://localhost:8000/api/v1/items/15 \
  -H "Accept: application/json" -H "Authorization: Bearer YOUR_TOKEN"
```

### Evaluate an item

`POST /items/{item}/evaluate` requires a bearer token and ownership of the item; another user's item returns **404**. It requires all four answers:

- `purchase_intent`: `need`, `want`, `replacement`, `upgrade`, `gift`
- `expected_usage_frequency`: `daily`, `several_times_week`, `weekly`, `monthly`, `rarely`
- `expected_usefulness`: `essential`, `very_useful`, `useful`, `nice_to_have`, `low_value`
- `affordability_answer`: `comfortable`, `unsure`, `uncomfortable`

Invalid or missing answers return **422**. Evaluation remains pre-purchase: item status is not changed and evaluating again replaces the previous result.

The deterministic Purchase Score is 0–100: usage (30 points), usefulness (25), affordability (25), and purchase intent (20). Verdict thresholds are excellent buy (90–100), good buy (75–89), probably worth it (60–74), think twice (40–59), probably skip (20–39), and skip (0–19). If a discretionary budget exists, affordability is reduced by the configured price-to-budget ratio; otherwise the direct affordability answer is used without penalty. The response also returns annual-use estimate, one-year cost per use, and estimated work hours when monthly income is available.

```bash
curl -X POST http://localhost:8000/api/v1/items/15/evaluate \
  -H "Accept: application/json" -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"purchase_intent":"upgrade","expected_usage_frequency":"daily","expected_usefulness":"very_useful","affordability_answer":"comfortable"}'
```

### Make a purchase decision

`POST /items/{item}/decision` requires a bearer token, ownership, and a completed evaluation (`purchase_score` and `evaluated_at`). Unevaluated items return **422**. Valid decisions are `buy`, `wait`, and `skip`.

- `buy` transitions the item to `purchased`; `skip` transitions it to `skipped`. Both are final and later decisions return **422**.
- `wait` requires integer `wait_days` from 1 to 90 and transitions to `waiting`. `reconsider_at` is set to the current time plus that many days. A waiting item can later be bought, skipped, or waited again.
- Supplying `wait_days` with `buy` or `skip` returns **422**.

Responses include `decision`, `decided_at`, `reconsider_at`, and computed `days_remaining`. Remaining days use ceil-style semantics: any positive partial day is `1`; expired waits are `0`; non-waiting items return `null`.

```bash
curl -X POST http://localhost:8000/api/v1/items/15/decision \
  -H "Accept: application/json" -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"decision":"wait","wait_days":7}'
```

```bash
curl -X POST http://localhost:8000/api/v1/items/15/decision \
  -H "Accept: application/json" -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"decision":"buy"}'
```

## Summary statistics

`GET /stats/summary` requires a bearer token and returns all-time data only for the authenticated user. It includes total items considered plus counts in `evaluating`, `waiting`, `purchased`, and `skipped` states.

Money Almost Spent is the sum of item prices only where both `status = skipped` and `decision = skip`. Totals are grouped by currency; no conversion or cross-currency total is calculated. The profile currency appears first when present and `primary_money_almost_spent` is that currency's skipped total, or `"0.00"` when it has none.

An empty account returns zero counts, its profile currency, `"0.00"`, and an empty `money_almost_spent` array.

```bash
curl http://localhost:8000/api/v1/stats/summary \
  -H "Accept: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN"
```

## Logout

`POST /logout` — requires a bearer token. Returns **200** and revokes only the token in that request. The same token then receives **401** from protected endpoints; tokens from other devices remain valid.

```bash
curl -X POST http://localhost:8000/api/v1/logout \
  -H "Accept: application/json" -H "Authorization: Bearer YOUR_TOKEN"
```
