// Primenza Go SDK v1
package primenza

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"
)

type Client struct {
	APIKey  string
	BaseURL string
	client  *http.Client
}

func New(apiKey string) *Client {
	return &Client{
		APIKey:  apiKey,
		BaseURL: "https://primenza.com/api/v1",
		client:  &http.Client{Timeout: 30 * time.Second},
	}
}

func (c *Client) request(method, path string, body interface{}) (map[string]interface{}, error) {
	var buf io.Reader
	if body != nil {
		b, _ := json.Marshal(body)
		buf = bytes.NewReader(b)
	}
	req, err := http.NewRequest(method, c.BaseURL+path, buf)
	if err != nil {
		return nil, err
	}
	req.Header.Set("Authorization", "Bearer "+c.APIKey)
	req.Header.Set("X-API-Key", c.APIKey)
	req.Header.Set("Content-Type", "application/json")
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var result map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&result)
	return result, nil
}

func (c *Client) Dashboard(domainID *int) (map[string]interface{}, error) {
	path := "/dashboard"
	if domainID != nil {
		path = fmt.Sprintf("/dashboard?domain_id=%d", *domainID)
	}
	return c.request("GET", path, nil)
}

func (c *Client) Domains() (map[string]interface{}, error)  { return c.request("GET", "/domains", nil) }
func (c *Client) Domain(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d", domainID), nil)
}
func (c *Client) CreateDomain(url string, name *string) (map[string]interface{}, error) {
	body := map[string]interface{}{"url": url}
	if name != nil {
		body["name"] = *name
	}
	return c.request("POST", "/domains", body)
}
func (c *Client) UpdateDomain(domainID int, fields map[string]interface{}) (map[string]interface{}, error) {
	return c.request("PATCH", fmt.Sprintf("/domains/%d", domainID), fields)
}
func (c *Client) Crawl(domainID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/crawl", domainID), nil)
}
func (c *Client) Audit(domainID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/audit", domainID), nil)
}
func (c *Client) Seo(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/seo", domainID), nil)
}
func (c *Client) RunSeo(domainID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/seo/run", domainID), nil)
}
func (c *Client) Geo(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/geo", domainID), nil)
}
func (c *Client) RunGeo(domainID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/geo/run", domainID), nil)
}
func (c *Client) AiVisibility(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/ai-visibility", domainID), nil)
}
func (c *Client) RunAiVisibility(domainID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/ai-visibility/run", domainID), nil)
}
func (c *Client) Performance(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/performance", domainID), nil)
}
func (c *Client) RunPerformance(domainID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/performance/run", domainID), nil)
}
func (c *Client) Links(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/links", domainID), nil)
}
func (c *Client) RunLinks(domainID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/links/run", domainID), nil)
}
func (c *Client) ContentGaps(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/content-gaps", domainID), nil)
}
func (c *Client) DiscoverContentGaps(domainID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/content-gaps/discover", domainID), nil)
}
func (c *Client) Competitors(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/competitors", domainID), nil)
}
func (c *Client) Monitoring(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/monitoring", domainID), nil)
}
func (c *Client) Reports(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/reports", domainID), nil)
}
func (c *Client) DeleteDomain(domainID int) (map[string]interface{}, error) {
	return c.request("DELETE", fmt.Sprintf("/domains/%d", domainID), nil)
}
func (c *Client) VerifyDomain(domainID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/verify", domainID), nil)
}
func (c *Client) DetectTech(domainID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/detect-tech", domainID), nil)
}
func (c *Client) Pages(domainID, page int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/pages?page=%d", domainID, page), nil)
}
func (c *Client) Audits(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/audits", domainID), nil)
}
func (c *Client) Schema(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/schema", domainID), nil)
}
func (c *Client) Robots(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/robots", domainID), nil)
}
func (c *Client) DeployRobots(domainID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/robots/deploy", domainID), nil)
}
func (c *Client) DeployLlms(domainID int, deployType string) (map[string]interface{}, error) {
	if deployType == "" {
		deployType = "llms"
	}
	return c.request("POST", fmt.Sprintf("/domains/%d/llms-txt/deploy", domainID), map[string]interface{}{"type": deployType})
}
func (c *Client) AddCompetitor(domainID int, url string) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/competitors", domainID), map[string]interface{}{"url": url})
}
func (c *Client) RefreshCompetitor(domainID, competitorID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/competitors/%d/refresh", domainID, competitorID), nil)
}
func (c *Client) RemoveCompetitor(domainID, competitorID int) (map[string]interface{}, error) {
	return c.request("DELETE", fmt.Sprintf("/domains/%d/competitors/%d", domainID, competitorID), nil)
}
func (c *Client) Tenant() (map[string]interface{}, error) {
	return c.request("GET", "/tenant", nil)
}
func (c *Client) Schedules() (map[string]interface{}, error) {
	return c.request("GET", "/schedules", nil)
}
func (c *Client) KnowledgeGraph(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/knowledge-graph", domainID), nil)
}
func (c *Client) BuildKnowledgeGraph(domainID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/knowledge-graph/build", domainID), nil)
}
func (c *Client) Citation(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/citation", domainID), nil)
}
func (c *Client) DeployPreview(domainID int, artifact string) (map[string]interface{}, error) {
	if artifact == "" {
		artifact = "robots"
	}
	return c.request("GET", fmt.Sprintf("/domains/%d/deploy/preview?artifact=%s", domainID, artifact), nil)
}
func (c *Client) Agents(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/agents", domainID), nil)
}
func (c *Client) RegisterAgent(domainID int, name, agentType string) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/agents", domainID), map[string]interface{}{"name": name, "type": agentType})
}
func (c *Client) TestWebhook() (map[string]interface{}, error) {
	return c.request("POST", "/webhooks/test", nil)
}
func (c *Client) GraphQL(query string, variables map[string]interface{}) (map[string]interface{}, error) {
	return c.request("POST", "/graphql", map[string]interface{}{"query": query, "variables": variables})
}

func (c *Client) CreateSchedule(data map[string]interface{}) (map[string]interface{}, error) {
	return c.request("POST", "/schedules", data)
}
func (c *Client) UpdateSchedule(id int, data map[string]interface{}) (map[string]interface{}, error) {
	return c.request("PATCH", fmt.Sprintf("/schedules/%d", id), data)
}
func (c *Client) DeleteSchedule(id int) (map[string]interface{}, error) {
	return c.request("DELETE", fmt.Sprintf("/schedules/%d", id), nil)
}
func (c *Client) Workspaces() (map[string]interface{}, error) {
	return c.request("GET", "/workspaces", nil)
}
func (c *Client) CreateWorkspace(data map[string]interface{}) (map[string]interface{}, error) {
	return c.request("POST", "/workspaces", data)
}
func (c *Client) UpdateWorkspace(id int, data map[string]interface{}) (map[string]interface{}, error) {
	return c.request("PATCH", fmt.Sprintf("/workspaces/%d", id), data)
}
func (c *Client) DeleteWorkspace(id int) (map[string]interface{}, error) {
	return c.request("DELETE", fmt.Sprintf("/workspaces/%d", id), nil)
}
func (c *Client) Team() (map[string]interface{}, error) {
	return c.request("GET", "/team", nil)
}
func (c *Client) InviteTeamMember(data map[string]interface{}) (map[string]interface{}, error) {
	return c.request("POST", "/team/invitations", data)
}
func (c *Client) UpdateTeamRole(userID int, role string) (map[string]interface{}, error) {
	return c.request("PATCH", fmt.Sprintf("/team/%d", userID), map[string]interface{}{"role": role})
}
func (c *Client) RemoveTeamMember(userID int) (map[string]interface{}, error) {
	return c.request("DELETE", fmt.Sprintf("/team/%d", userID), nil)
}
func (c *Client) CancelInvitation(invitationID int) (map[string]interface{}, error) {
	return c.request("DELETE", fmt.Sprintf("/team/invitations/%d", invitationID), nil)
}
func (c *Client) Settings() (map[string]interface{}, error) {
	return c.request("GET", "/settings", nil)
}
func (c *Client) UpdateSettings(data map[string]interface{}) (map[string]interface{}, error) {
	return c.request("PATCH", "/settings", data)
}
func (c *Client) CreateApiKey(data map[string]interface{}) (map[string]interface{}, error) {
	return c.request("POST", "/api-keys", data)
}
func (c *Client) DeleteApiKey(id int) (map[string]interface{}, error) {
	return c.request("DELETE", fmt.Sprintf("/api-keys/%d", id), nil)
}
func (c *Client) AuditLogs(query string) (map[string]interface{}, error) {
	path := "/audit-logs"
	if query != "" {
		path = fmt.Sprintf("/audit-logs?%s", query)
	}
	return c.request("GET", path, nil)
}
func (c *Client) Notifications() (map[string]interface{}, error) {
	return c.request("GET", "/notifications", nil)
}
func (c *Client) MarkNotificationRead(id int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/notifications/%d/read", id), nil)
}
func (c *Client) MarkAllNotificationsRead() (map[string]interface{}, error) {
	return c.request("POST", "/notifications/read-all", nil)
}
func (c *Client) RegenerateVerification(domainID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/verification/regenerate", domainID), nil)
}
func (c *Client) UpdateVerificationMethod(domainID int, method string) (map[string]interface{}, error) {
	return c.request("PATCH", fmt.Sprintf("/domains/%d/verification-method", domainID), map[string]interface{}{"method": method})
}
func (c *Client) ActivateDomain(domainID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/activate", domainID), nil)
}
func (c *Client) GenerateContentGapOutline(domainID, gapID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/content-gaps/%d/outline", domainID, gapID), nil)
}
func (c *Client) GenerateContentGapArticle(domainID, gapID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/content-gaps/%d/article", domainID, gapID), nil)
}
func (c *Client) DismissContentGap(domainID, gapID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/content-gaps/%d/dismiss", domainID, gapID), nil)
}
func (c *Client) ContentOptimizer(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/content-optimizer", domainID), nil)
}
func (c *Client) RefreshContentOptimizer(domainID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/content-optimizer/refresh", domainID), nil)
}
func (c *Client) SimulateAiVisibility(domainID int, data map[string]interface{}) (map[string]interface{}, error) {
	if data == nil {
		data = map[string]interface{}{}
	}
	return c.request("POST", fmt.Sprintf("/domains/%d/ai-visibility/simulate", domainID), data)
}
func (c *Client) InstallAgent(domainID int, data map[string]interface{}) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/agents/install", domainID), data)
}
func (c *Client) GenerateSchema(domainID int, data map[string]interface{}) (map[string]interface{}, error) {
	if data == nil {
		data = map[string]interface{}{}
	}
	return c.request("POST", fmt.Sprintf("/domains/%d/schema/generate", domainID), data)
}
func (c *Client) DeploySchema(domainID int, data map[string]interface{}) (map[string]interface{}, error) {
	if data == nil {
		data = map[string]interface{}{}
	}
	return c.request("POST", fmt.Sprintf("/domains/%d/schema/deploy", domainID), data)
}
func (c *Client) UpdateRobots(domainID int, content string) (map[string]interface{}, error) {
	return c.request("PUT", fmt.Sprintf("/domains/%d/robots", domainID), map[string]interface{}{"content": content})
}
func (c *Client) GenerateLlms(domainID int, deployType string) (map[string]interface{}, error) {
	if deployType == "" {
		deployType = "llms"
	}
	return c.request("POST", fmt.Sprintf("/domains/%d/llms-txt/generate", domainID), map[string]interface{}{"type": deployType})
}
func (c *Client) StoreSubdomain(domainID int, data map[string]interface{}) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/subdomains", domainID), data)
}
func (c *Client) DestroySubdomain(domainID, subdomainID int) (map[string]interface{}, error) {
	return c.request("DELETE", fmt.Sprintf("/domains/%d/subdomains/%d", domainID, subdomainID), nil)
}
func (c *Client) DownloadReport(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/reports/download", domainID), nil)
}
func (c *Client) DownloadReportPdf(domainID int) (map[string]interface{}, error) {
	return c.request("GET", fmt.Sprintf("/domains/%d/reports/download/pdf", domainID), nil)
}
func (c *Client) SuggestCitation(domainID, pageID int, data map[string]interface{}) (map[string]interface{}, error) {
	if data == nil {
		data = map[string]interface{}{}
	}
	return c.request("POST", fmt.Sprintf("/domains/%d/citation/%d/suggest", domainID, pageID), data)
}
func (c *Client) ApproveAgentCommand(domainID, commandID int) (map[string]interface{}, error) {
	return c.request("POST", fmt.Sprintf("/domains/%d/agents/commands/%d/approve", domainID, commandID), nil)
}

type AgentClient struct {
	AgentToken string
	BaseURL    string
	client     *http.Client
}

func NewAgent(agentToken string) *AgentClient {
	return &AgentClient{
		AgentToken: agentToken,
		BaseURL:    "https://primenza.com/api/v1",
		client:     &http.Client{Timeout: 30 * time.Second},
	}
}

func (c *AgentClient) request(method, path string, body interface{}) (map[string]interface{}, error) {
	var buf io.Reader
	if body != nil {
		b, _ := json.Marshal(body)
		buf = bytes.NewReader(b)
	}
	req, err := http.NewRequest(method, c.BaseURL+path, buf)
	if err != nil {
		return nil, err
	}
	req.Header.Set("X-Agent-Token", c.AgentToken)
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json")
	resp, err := c.client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	var result map[string]interface{}
	json.NewDecoder(resp.Body).Decode(&result)
	return result, nil
}

func (c *AgentClient) Poll() (map[string]interface{}, error) {
	return c.request("POST", "/agent/poll", nil)
}

func (c *AgentClient) Report(commandID int, result interface{}) (map[string]interface{}, error) {
	return c.request("POST", "/agent/report", map[string]interface{}{"command_id": commandID, "result": result})
}
