syntax = "v1"

type (
	ResearchItemData {
		Title   string `json:"title,omitempty"`
		URL     string `json:"url,omitempty"`
		Snippet string `json:"snippet,omitempty"`
		Query   string `json:"query,omitempty"`
	}

	ResearchMapData {
		AudienceSummary string             `json:"audience_summary,omitempty"`
		ContentGoal     string             `json:"content_goal,omitempty"`
		Questions       []string           `json:"questions,omitempty"`
		Pillars         []string           `json:"pillars,omitempty"`
		Exclusions      []string           `json:"exclusions,omitempty"`
		ResearchItems   []ResearchItemData `json:"research_items,omitempty"`
		ExpandStrategy  string             `json:"expand_strategy,omitempty"`
		PatrolKeywords  []string           `json:"patrol_keywords,omitempty"`
	}

	KnowledgeGraphEvidenceData {
		URL     string `json:"url,omitempty"`
		Snippet string `json:"snippet,omitempty"`
		Query   string `json:"query,omitempty"`
	}

	BraveSourceData {
		Query   string `json:"query,omitempty"`
		Title   string `json:"title,omitempty"`
		URL     string `json:"url,omitempty"`
		Snippet string `json:"snippet,omitempty"`
	}

	BrandProductData {
		ID             string   `json:"id"`
		Label          string   `json:"label"`
		ProductContext string   `json:"product_context"`
		MatchTags      []string `json:"match_tags,omitempty"`
		CreateAt       int64    `json:"create_at"`
		UpdateAt       int64    `json:"update_at"`
	}

	BrandData {
		ID             string             `json:"id"`
		DisplayName    string             `json:"display_name,omitempty"`
		TopicName      string             `json:"topic_name,omitempty"`
		SeedQuery      string             `json:"seed_query,omitempty"`
		Brief          string             `json:"brief,omitempty"`
		ProductBrief   string             `json:"product_brief,omitempty"`
		ProductContext string             `json:"product_context,omitempty"`
		ProductID      string             `json:"product_id,omitempty"`
		Products       []BrandProductData `json:"products,omitempty"`
		TargetAudience string             `json:"target_audience,omitempty"`
		Goals          string             `json:"goals,omitempty"`
		ResearchMap    ResearchMapData    `json:"research_map,omitempty"`
		CreateAt       int64              `json:"create_at"`
		UpdateAt       int64              `json:"update_at"`
	}

	ListBrandProductsData {
		List []BrandProductData `json:"list"`
	}

	CreateBrandProductReq {
		Label          string   `json:"label" validate:"required"`
		ProductContext string   `json:"product_context" validate:"required"`
		MatchTags      []string `json:"match_tags,optional"`
	}

	UpdateBrandProductReq {
		Label          *string  `json:"label,optional"`
		ProductContext *string  `json:"product_context,optional"`
		MatchTags      []string `json:"match_tags,optional"`
	}

	BrandProductPath {
		ID        string `path:"id" validate:"required"`
		ProductID string `path:"productId" validate:"required"`
	}

	CreateBrandProductHandlerReq {
		BrandPath
		CreateBrandProductReq
	}

	UpdateBrandProductHandlerReq {
		BrandProductPath
		UpdateBrandProductReq
	}

	ListBrandsData {
		List []BrandData `json:"list"`
	}

	CreateBrandReq {
		DisplayName string `json:"display_name,optional"`
	}

	BrandPath {
		ID string `path:"id" validate:"required"`
	}

	UpdateBrandReq {
		DisplayName      *string  `json:"display_name,optional"`
		TopicName        *string  `json:"topic_name,optional"`
		SeedQuery        *string  `json:"seed_query,optional"`
		Brief            *string  `json:"brief,optional"`
		ProductBrief     *string  `json:"product_brief,optional"`
		ProductContext   *string  `json:"product_context,optional"`
		ProductID        *string  `json:"product_id,optional"`
		TargetAudience   *string  `json:"target_audience,optional"`
		Goals            *string  `json:"goals,optional"`
		AudienceSummary  *string  `json:"audience_summary,optional"`
		ContentGoal      *string  `json:"content_goal,optional"`
		Questions        []string `json:"questions,optional"`
		Pillars          []string `json:"pillars,optional"`
		Exclusions       []string `json:"exclusions,optional"`
		PatrolKeywords   []string `json:"patrol_keywords,optional"`
	}

	KnowledgeGraphNodeData {
		ID              string                       `json:"id"`
		Label           string                       `json:"label"`
		NodeKind        string                       `json:"node_kind"`
		Type            string                       `json:"type"`
		Layer           int                          `json:"layer"`
		Relation        string                       `json:"relation,omitempty"`
		PlacementValue  string                       `json:"placement_value,omitempty"`
		ProductFitScore int                          `json:"product_fit_score"`
		SelectedForScan bool                         `json:"selected_for_scan"`
		RelevanceTags   []string                     `json:"relevance_tags"`
		RecencyTags     []string                     `json:"recency_tags"`
		Evidence        []KnowledgeGraphEvidenceData `json:"evidence,omitempty"`
	}

	KnowledgeGraphEdgeData {
		From     string `json:"from"`
		To       string `json:"to"`
		Relation string `json:"relation"`
	}

	KnowledgeGraphData {
		ID             string                   `json:"id"`
		BrandID        string                   `json:"brand_id"`
		Seed           string                   `json:"seed"`
		Nodes          []KnowledgeGraphNodeData `json:"nodes"`
		Edges          []KnowledgeGraphEdgeData `json:"edges"`
		BraveSources   []BraveSourceData        `json:"brave_sources,omitempty"`
		ExpandStrategy string                   `json:"expand_strategy,omitempty"`
		PainTagCount   int                      `json:"pain_tag_count"`
		GeneratedAt    int64                    `json:"generated_at"`
		CreateAt       int64                    `json:"create_at"`
		UpdateAt       int64                    `json:"update_at"`
	}

	ExpandKnowledgeGraphReq {
		SeedQuery       string `json:"seed_query" validate:"required"`
		Supplemental    bool   `json:"supplemental,optional"`
		RegenerateMap   bool   `json:"regenerate_map,optional"`
		ExpandStrategy  string `json:"expand_strategy,optional"` // brave | llm | hybrid
	}

	ExpandKnowledgeGraphData {
		JobID   string `json:"job_id"`
		Status  string `json:"status"`
		Message string `json:"message"`
	}

	KnowledgeGraphNodeUpdate {
		NodeID          string   `json:"node_id" validate:"required"`
		SelectedForScan *bool    `json:"selected_for_scan,optional"`
		RelevanceTags   []string `json:"relevance_tags,optional"`
		RecencyTags     []string `json:"recency_tags,optional"`
	}

	PatchKnowledgeGraphNodesReq {
		Updates []KnowledgeGraphNodeUpdate `json:"updates" validate:"required"`
	}

	StartBrandScanJobReq {
		GraphID        string   `json:"graph_id,optional"`
		NodeIDs        []string `json:"node_ids,optional"`
		DualTrack      bool     `json:"dual_track,optional"`
		PatrolMode     bool     `json:"patrol_mode,optional"`
		PatrolKeywords []string `json:"patrol_keywords,optional"`
	}

	StartBrandScanJobData {
		JobID   string `json:"job_id"`
		Status  string `json:"status"`
		Message string `json:"message"`
	}

	ListBrandScanPostsReq {
		Priority      string `form:"priority,optional"`
		Recent7d      bool   `form:"recent_7d,optional"`
		ProductFitMin int    `form:"product_fit_min,optional"`
		Limit         int    `form:"limit,optional"`
	}

	ScanPostData {
		ID                 string `json:"id"`
		GraphNodeID        string `json:"graph_node_id"`
		SearchTag          string `json:"search_tag"`
		QueryDimension     string `json:"query_dimension"`
		ExternalID         string `json:"external_id"`
		Permalink          string `json:"permalink"`
		Author             string `json:"author"`
		Text               string `json:"text"`
		Priority           string `json:"priority"`
		PlacementScore     int    `json:"placement_score"`
		ProductFitScore    int    `json:"product_fit_score"`
		SolvedByProduct    bool   `json:"solved_by_product"`
		Source             string `json:"source"`
		ScanJobID          string `json:"scan_job_id"`
		OutreachStatus     string `json:"outreach_status,omitempty"`
		PublishedReplyID   string `json:"published_reply_id,omitempty"`
		PublishedPermalink string `json:"published_permalink,omitempty"`
		OutreachUpdateAt   int64           `json:"outreach_update_at,omitempty"`
		PostedAt           string          `json:"posted_at,omitempty"`
		Replies            []ScanReplyData `json:"replies,omitempty"`
		LatestDraft        *GenerateOutreachDraftsData `json:"latest_draft,omitempty"`
		CreateAt           int64           `json:"create_at"`
	}

	ListBrandScanPostsData {
		List  []ScanPostData `json:"list"`
		Total int            `json:"total"`
	}

	GenerateOutreachDraftsReq {
		ScanPostID      string `json:"scan_post_id" validate:"required"`
		TopicID         string `json:"topic_id,optional"`
		Count           int    `json:"count,optional"`
		VoicePersonaID  string `json:"voice_persona_id,optional"`
		ProductID       string `json:"product_id,optional"`
	}

	OutreachDraftItemData {
		Text      string `json:"text"`
		Angle     string `json:"angle"`
		Rationale string `json:"rationale"`
	}

	GenerateOutreachDraftsData {
		ID         string                `json:"id"`
		ScanPostID string                `json:"scan_post_id"`
		Relevance  float64               `json:"relevance"`
		Reason     string                `json:"reason"`
		Drafts     []OutreachDraftItemData `json:"drafts"`
		CreateAt   int64                 `json:"create_at"`
	}

	PublishOutreachDraftReq {
		ScanPostID string `json:"scan_post_id" validate:"required"`
		Text       string `json:"text" validate:"required"`
		Confirm    bool   `json:"confirm"`
	}

	PublishOutreachDraftData {
		ScanPostID         string `json:"scan_post_id"`
		ReplyID            string `json:"reply_id"`
		Permalink          string `json:"permalink"`
		OutreachStatus     string `json:"outreach_status"`
		PublishedPermalink string `json:"published_permalink"`
		Message            string `json:"message"`
	}

	PatchScanPostOutreachReq {
		OutreachStatus *string `json:"outreach_status,optional"`
	}

	ContentMatrixRowData {
		SortOrder        int      `json:"sort_order"`
		SearchTag        string   `json:"search_tag"`
		Angle            string   `json:"angle"`
		Hook             string   `json:"hook"`
		Text             string   `json:"text"`
		ReferenceNotes   string   `json:"reference_notes"`
		SourcePermalinks []string `json:"source_permalinks"`
		Rationale        string   `json:"rationale"`
	}

	ContentMatrixData {
		ID          string                 `json:"id,omitempty"`
		BrandID     string                 `json:"brand_id"`
		Rows        []ContentMatrixRowData `json:"rows"`
		GeneratedAt int64                  `json:"generated_at"`
		CreateAt    int64                  `json:"create_at,omitempty"`
		UpdateAt    int64                  `json:"update_at,omitempty"`
	}

	GenerateContentMatrixReq {
		Count int `json:"count,optional"`
	}

	ScanReplyData {
		ExternalID string `json:"external_id,omitempty"`
		Author     string `json:"author,omitempty"`
		Text       string `json:"text"`
		Permalink  string `json:"permalink,omitempty"`
		LikeCount  int    `json:"like_count,omitempty"`
		PostedAt   string `json:"posted_at,omitempty"`
	}

	BrandScanScheduleData {
		ID        string `json:"id,omitempty"`
		BrandID   string `json:"brand_id"`
		Cron      string `json:"cron"`
		Timezone  string `json:"timezone"`
		Enabled   bool   `json:"enabled"`
		NextRunAt int64  `json:"next_run_at,omitempty"`
		LastRunAt int64  `json:"last_run_at,omitempty"`
	}

	UpsertBrandScanScheduleReq {
		Cron     string `json:"cron,optional"`
		Timezone string `json:"timezone,optional"`
		Enabled  bool   `json:"enabled"`
	}

	UpdateBrandHandlerReq {
		BrandPath
		UpdateBrandReq
	}

	ExpandKnowledgeGraphHandlerReq {
		BrandPath
		ExpandKnowledgeGraphReq
	}

	PatchKnowledgeGraphNodesHandlerReq {
		BrandPath
		PatchKnowledgeGraphNodesReq
	}

	StartBrandScanJobHandlerReq {
		BrandPath
		StartBrandScanJobReq
	}

	ListBrandScanPostsHandlerReq {
		BrandPath
		ListBrandScanPostsReq
	}

	GenerateOutreachDraftsHandlerReq {
		BrandPath
		GenerateOutreachDraftsReq
	}

	PublishOutreachDraftHandlerReq {
		BrandPath
		PublishOutreachDraftReq
	}

	PatchScanPostOutreachHandlerReq {
		BrandPath
		PostID string `path:"postId"`
		PatchScanPostOutreachReq
	}

	GenerateContentMatrixHandlerReq {
		BrandPath
		GenerateContentMatrixReq
	}

	UpsertBrandScanScheduleHandlerReq {
		BrandPath
		UpsertBrandScanScheduleReq
	}
)

@server(
	group:      brand
	prefix:     /api/v1/brands
	middleware: AuthJWT
	tags:       "Brand"
	summary:    "Brand profiles for placement workflow. Requires Bearer JWT."
)
service gateway {
	@handler listBrands
	get / returns (ListBrandsData)

	@handler createBrand
	post / (CreateBrandReq) returns (BrandData)

	@handler getBrand
	get /:id (BrandPath) returns (BrandData)

	@handler updateBrand
	patch /:id (UpdateBrandHandlerReq) returns (BrandData)

	@handler deleteBrand
	delete /:id (BrandPath)

	@handler listBrandProducts
	get /:id/products (BrandPath) returns (ListBrandProductsData)

	@handler createBrandProduct
	post /:id/products (CreateBrandProductHandlerReq) returns (BrandProductData)

	@handler updateBrandProduct
	patch /:id/products/:productId (UpdateBrandProductHandlerReq) returns (BrandProductData)

	@handler deleteBrandProduct
	delete /:id/products/:productId (BrandProductPath)

	@handler expandKnowledgeGraph
	post /:id/knowledge-graph/expand (ExpandKnowledgeGraphHandlerReq) returns (ExpandKnowledgeGraphData)

	@handler getKnowledgeGraph
	get /:id/knowledge-graph (BrandPath) returns (KnowledgeGraphData)

	@handler patchKnowledgeGraphNodes
	patch /:id/knowledge-graph/nodes (PatchKnowledgeGraphNodesHandlerReq) returns (KnowledgeGraphData)

	@handler startBrandScanJob
	post /:id/scan-jobs (StartBrandScanJobHandlerReq) returns (StartBrandScanJobData)

	@handler listBrandScanPosts
	get /:id/scan-posts (ListBrandScanPostsHandlerReq) returns (ListBrandScanPostsData)

	@handler generateOutreachDrafts
	post /:id/outreach-drafts/generate (GenerateOutreachDraftsHandlerReq) returns (GenerateOutreachDraftsData)

	@handler publishOutreachDraft
	post /:id/outreach-drafts/publish (PublishOutreachDraftHandlerReq) returns (PublishOutreachDraftData)

	@handler patchScanPostOutreach
	patch /:id/scan-posts/:postId (PatchScanPostOutreachHandlerReq) returns (ScanPostData)

	@handler getBrandContentMatrix
	get /:id/content-matrix (BrandPath) returns (ContentMatrixData)

	@handler generateBrandContentMatrix
	post /:id/content-matrix/generate (GenerateContentMatrixHandlerReq) returns (ContentMatrixData)

	@handler getBrandScanSchedule
	get /:id/scan-schedule (BrandPath) returns (BrandScanScheduleData)

	@handler upsertBrandScanSchedule
	put /:id/scan-schedule (UpsertBrandScanScheduleHandlerReq) returns (BrandScanScheduleData)
}
