{
  "openapi": "3.0.3",
  "info": {
    "title": "CarModPlanner Public API",
    "version": "1.0.0",
    "description": "Read-mostly REST API powering the CarModPlanner 2022 Dodge Challenger build planner. Most endpoints are unauthenticated today; OAuth scopes (read:catalog, write:builds) are stubbed at /.well-known/oauth-authorization-server and will become real in a future release.",
    "contact": { "name": "CarModPlanner", "url": "https://carmodplanner.com" },
    "license": { "name": "Proprietary" }
  },
  "servers": [
    { "url": "https://carmodplanner.com", "description": "Production" }
  ],
  "tags": [
    { "name": "catalog", "description": "Parts, categories, retailer prices" },
    { "name": "builds", "description": "Public build storage + compatibility evaluation" },
    { "name": "canonical", "description": "Canonical product / system / component graph" },
    { "name": "ops", "description": "Health + meta" }
  ],
  "paths": {
    "/api/health": {
      "get": {
        "tags": ["ops"],
        "summary": "Service health probe",
        "responses": {
          "200": {
            "description": "Always 200 when the Next.js process is responsive",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["status"],
                  "properties": {
                    "status": { "type": "string", "example": "ok" },
                    "service": { "type": "string", "example": "carmodplanner" },
                    "version": { "type": "string", "example": "1.0.0" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/categories": {
      "get": {
        "tags": ["catalog"],
        "summary": "List part categories",
        "description": "Returns every category with its subcategories and a count of parts in each.",
        "responses": {
          "200": {
            "description": "Array of categories ordered by sortOrder",
            "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Category" } } } }
          }
        }
      }
    },
    "/api/parts": {
      "get": {
        "tags": ["catalog"],
        "summary": "Search / list parts",
        "parameters": [
          { "name": "search",      "in": "query", "schema": { "type": "string" }, "description": "Free-text match against name + brand" },
          { "name": "category",    "in": "query", "schema": { "type": "string" }, "description": "Category slug filter" },
          { "name": "subcategory", "in": "query", "schema": { "type": "string" }, "description": "Subcategory slug filter" },
          { "name": "brand",       "in": "query", "schema": { "type": "string" }, "description": "Exact brand name match" },
          { "name": "ids",         "in": "query", "schema": { "type": "string" }, "description": "Comma-separated part IDs for bulk lookup" },
          { "name": "limit",       "in": "query", "schema": { "type": "integer", "default": 24, "maximum": 200 } }
        ],
        "responses": {
          "200": {
            "description": "Array of parts matching the filters (empty array when no match)",
            "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Part" } } } }
          }
        }
      }
    },
    "/api/builds": {
      "post": {
        "tags": ["builds"],
        "summary": "Create a public build",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name", "partIds"],
                "properties": {
                  "name":        { "type": "string", "maxLength": 100 },
                  "description": { "type": "string", "maxLength": 500 },
                  "authorName":  { "type": "string", "maxLength": 60 },
                  "trim":        { "type": "string", "enum": ["sxt-3-6", "rt-5-7", "scatpack-6-4", "hellcat-6-2sc"] },
                  "partIds":     { "type": "array", "items": { "type": "integer" } }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Build created", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "integer" }, "name": { "type": "string" } } } } } },
          "400": { "description": "Validation failed" },
          "429": { "description": "Rate limited" }
        }
      }
    },
    "/api/build-check": {
      "post": {
        "tags": ["builds"],
        "summary": "Evaluate compatibility of a candidate build",
        "description": "Runs the canonical v2 evaluator against a list of part IDs and returns blocks, errors, warnings, recommendations, and per-component coverage state.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["partIds"],
                "properties": {
                  "partIds":                 { "type": "array", "items": { "type": "integer" } },
                  "variantSlug":             { "type": "string", "description": "Optional trim variant; narrows the rule set" },
                  "preExistingComponentIds": { "type": "array", "items": { "type": "integer" } }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Evaluation report",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EvaluationResponse" } } }
          }
        }
      }
    },
    "/api/price-history": {
      "get": {
        "tags": ["catalog"],
        "summary": "Price history for a part",
        "parameters": [
          { "name": "partId", "in": "query", "required": true, "schema": { "type": "integer" } },
          { "name": "days",   "in": "query", "schema": { "type": "integer", "default": 90, "maximum": 365 } }
        ],
        "responses": {
          "200": {
            "description": "History + current retailer prices + min/max stats",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "history": { "type": "array", "items": { "$ref": "#/components/schemas/PriceHistoryRow" } }, "current": { "type": "array", "items": { "$ref": "#/components/schemas/RetailerPrice" } }, "stats": { "$ref": "#/components/schemas/PriceStats" } } } } }
          }
        }
      }
    },
    "/api/canonical/products": {
      "get": {
        "tags": ["canonical"],
        "summary": "List canonical products",
        "parameters": [
          { "name": "ids",           "in": "query", "schema": { "type": "string" }, "description": "Comma-separated CanonicalProduct IDs" },
          { "name": "legacyIds",     "in": "query", "schema": { "type": "string" }, "description": "Comma-separated legacy Part IDs" },
          { "name": "componentSlug", "in": "query", "schema": { "type": "string" } },
          { "name": "variantSlug",   "in": "query", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Canonical products with brand, coverage, trims", "content": { "application/json": { "schema": { "type": "object", "properties": { "products": { "type": "array", "items": { "$ref": "#/components/schemas/CanonicalProduct" } } } } } } }
        }
      }
    },
    "/api/canonical/systems": {
      "get": {
        "tags": ["canonical"],
        "summary": "Get the canonical systems hierarchy",
        "description": "Returns the full Layer 1 systems > subsystems > components tree the build planner uses.",
        "responses": {
          "200": { "description": "Hierarchy", "content": { "application/json": { "schema": { "type": "object", "properties": { "systems": { "type": "array", "items": { "$ref": "#/components/schemas/CanonicalSystem" } } } } } } }
        }
      }
    },
    "/api/canonical/evaluate": {
      "post": {
        "tags": ["canonical"],
        "summary": "Evaluate a build at the canonical layer",
        "description": "Same evaluator as /api/build-check but accepts CanonicalProduct IDs directly instead of legacy Part IDs.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "productIds":              { "type": "array", "items": { "type": "integer" } },
                  "legacyPartIds":           { "type": "array", "items": { "type": "integer" } },
                  "preExistingComponentIds": { "type": "array", "items": { "type": "integer" } },
                  "variantSlug":             { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Evaluation report", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EvaluationResponse" } } } }
        }
      }
    },
    "/api/og/build": {
      "get": {
        "tags": ["ops"],
        "summary": "Open Graph image for a shareable build",
        "parameters": [
          { "name": "parts",     "in": "query", "schema": { "type": "string" }, "description": "Comma-separated legacy Part IDs" },
          { "name": "canonical", "in": "query", "schema": { "type": "string" }, "description": "Comma-separated CanonicalProduct IDs" },
          { "name": "name",      "in": "query", "schema": { "type": "string" } },
          { "name": "trim",      "in": "query", "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "1200x630 OG image (PNG)",
            "content": { "image/png": { "schema": { "type": "string", "format": "binary" } } }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Category": {
        "type": "object",
        "properties": {
          "id":   { "type": "integer" },
          "name": { "type": "string" },
          "slug": { "type": "string" },
          "description": { "type": "string", "nullable": true },
          "subcategories": { "type": "array", "items": { "$ref": "#/components/schemas/Subcategory" } },
          "_count": { "type": "object", "properties": { "parts": { "type": "integer" } } }
        }
      },
      "Subcategory": {
        "type": "object",
        "properties": {
          "id":   { "type": "integer" },
          "name": { "type": "string" },
          "slug": { "type": "string" },
          "description": { "type": "string", "nullable": true }
        }
      },
      "Part": {
        "type": "object",
        "properties": {
          "id":           { "type": "integer" },
          "name":         { "type": "string" },
          "brand":        { "type": "string" },
          "sku":          { "type": "string", "nullable": true },
          "priceMin":     { "type": "number", "format": "float" },
          "priceMax":     { "type": "number", "format": "float", "nullable": true },
          "hpGain":       { "type": "integer", "nullable": true },
          "tqGain":       { "type": "integer", "nullable": true },
          "peakHp":       { "type": "integer", "nullable": true, "description": "Total output (forced-induction kits)" },
          "peakTq":       { "type": "integer", "nullable": true },
          "isForcedInduction": { "type": "boolean" },
          "weight":       { "type": "number", "nullable": true },
          "weightDelta":  { "type": "number", "nullable": true },
          "imageUrl":     { "type": "string", "nullable": true },
          "manufacturerUrl": { "type": "string", "nullable": true },
          "subcategory":  { "$ref": "#/components/schemas/Subcategory" }
        }
      },
      "PriceHistoryRow": {
        "type": "object",
        "properties": {
          "id":        { "type": "integer" },
          "partId":    { "type": "integer" },
          "price":     { "type": "number" },
          "retailer":  { "type": "string" },
          "observedAt":{ "type": "string", "format": "date-time" }
        }
      },
      "RetailerPrice": {
        "type": "object",
        "properties": {
          "retailer": { "type": "string" },
          "price":    { "type": "number" },
          "url":      { "type": "string" },
          "inStock":  { "type": "boolean" }
        }
      },
      "PriceStats": {
        "type": "object",
        "properties": {
          "min":      { "type": "number" },
          "max":      { "type": "number" },
          "current":  { "type": "number" },
          "isLowest": { "type": "boolean" }
        }
      },
      "CanonicalProduct": {
        "type": "object",
        "properties": {
          "id":            { "type": "integer" },
          "slug":          { "type": "string" },
          "canonicalName": { "type": "string" },
          "brand":         { "type": "string" },
          "trims":         { "type": "array", "items": { "type": "string" } },
          "imageUrl":      { "type": "string", "nullable": true }
        }
      },
      "CanonicalSystem": {
        "type": "object",
        "properties": {
          "slug":        { "type": "string" },
          "name":        { "type": "string" },
          "subsystems":  { "type": "array", "items": { "type": "object" } }
        }
      },
      "EvaluationResponse": {
        "type": "object",
        "properties": {
          "report": {
            "type": "object",
            "properties": {
              "evaluator": { "type": "string", "example": "v2-canonical" },
              "blocks":          { "type": "array", "items": { "$ref": "#/components/schemas/RuleEvaluation" } },
              "errors":          { "type": "array", "items": { "$ref": "#/components/schemas/RuleEvaluation" } },
              "warnings":        { "type": "array", "items": { "$ref": "#/components/schemas/RuleEvaluation" } },
              "recommendations": { "type": "array", "items": { "$ref": "#/components/schemas/RuleEvaluation" } },
              "satisfiedRules":  { "type": "array", "items": { "$ref": "#/components/schemas/RuleEvaluation" } },
              "componentStates": { "type": "array", "items": { "type": "object" } }
            }
          },
          "unmappedLegacyPartIds": { "type": "array", "items": { "type": "integer" } }
        }
      },
      "RuleEvaluation": {
        "type": "object",
        "properties": {
          "ruleSlug": { "type": "string" },
          "severity": { "type": "string", "enum": ["block", "error", "warning", "recommendation", "info"] },
          "message":  { "type": "string" },
          "involvedComponentSlugs": { "type": "array", "items": { "type": "string" } },
          "involvedProductIds":     { "type": "array", "items": { "type": "integer" } },
          "satisfied": { "type": "boolean" }
        }
      }
    }
  }
}
