package webui

import (
	"net/http"
	"strconv"
	"strings"

	"mailgoserver/internal/db"
)

var validConditionFields = map[string]bool{
	"from": true, "to": true, "subject": true,
	"body": true, "has_attachment": true, "recipient_type": true,
}
var validConditionOps = map[string]bool{"contains": true, "equals": true, "starts_with": true}
var validActions = map[string]bool{
	"move_to_folder": true, "delete": true, "mark_read": true, "mark_as_spam": true, "forward": true,
}

// parseRuleConditions reads the rule-builder's parallel condition_field/op/value
// arrays (one value per condition row, same index across all three) — shared by the
// admin and self-service "add rule" handlers, which both submit the same form shape.
// r.ParseForm() must already have been called.
func parseRuleConditions(r *http.Request) ([]db.RuleCondition, bool) {
	fields := r.PostForm["condition_field"]
	ops := r.PostForm["condition_op"]
	values := r.PostForm["condition_value"]
	if len(fields) == 0 || len(fields) != len(ops) || len(fields) != len(values) {
		return nil, false
	}
	conditions := make([]db.RuleCondition, 0, len(fields))
	for i, field := range fields {
		op := ops[i]
		value := strings.TrimSpace(values[i])
		if !validConditionFields[field] || !validConditionOps[op] || value == "" {
			return nil, false
		}
		conditions = append(conditions, db.RuleCondition{Field: field, Op: op, Value: value})
	}
	return conditions, true
}

var conditionFieldLabels = map[string]string{
	"from": "from", "to": "to", "subject": "subject", "body": "body",
	"has_attachment": "has attachment", "recipient_type": "I'm on the",
}

// summarizeConditions renders a rule's condition list as a human-readable string for
// display, e.g. `to contains "sales" AND subject contains "invoice"`. A "\n"-joined
// multi-value condition (the rule builder's chip input) renders as a quoted,
// comma-separated list, e.g. `from is any of "a@x.com, b@y.com"`.
func summarizeConditions(r db.MailboxFilterRule) string {
	conditions, matchType := r.Conditions()
	joiner := " AND "
	if matchType == "any" {
		joiner = " OR "
	}
	parts := make([]string, len(conditions))
	for i, c := range conditions {
		label := conditionFieldLabels[c.Field]
		if label == "" {
			label = c.Field
		}
		values := strings.Split(c.Value, "\n")
		switch c.Field {
		case "has_attachment":
			parts[i] = label + ": " + c.Value
		case "recipient_type":
			parts[i] = label + " " + strings.ToUpper(c.Value) + " line"
		case "":
			parts[i] = ""
		default:
			op := strings.ReplaceAll(c.Op, "_", " ")
			if len(values) > 1 {
				op = "is any of"
			}
			parts[i] = label + " " + op + ` "` + strings.Join(values, ", ") + `"`
		}
	}
	return strings.Join(parts, joiner)
}

func (a *App) rulesList(w http.ResponseWriter, r *http.Request) {
	mailbox, ok := a.mailboxWithAccess(w, r)
	if !ok {
		return
	}
	rules, err := a.DB.ListRulesForMailbox(mailbox.ID)
	if err != nil {
		setFlash(w, "error", "Error loading rules")
	}
	a.render(w, r, "mailbox_rules.html", M{"active": "mailboxes", "mailbox": mailbox, "rules": rules})
}

// addRule mirrors the compact list-CRUD pattern used elsewhere: no separate edit
// page, just add/remove — a rule needing changes is removed and re-added.
func (a *App) addRule(w http.ResponseWriter, r *http.Request) {
	mailbox, ok := a.mailboxWithAccess(w, r)
	if !ok {
		return
	}
	if err := r.ParseForm(); err != nil {
		setFlash(w, "error", "Invalid form submission")
		http.Redirect(w, r, Prefix+"/mailboxes/"+idStr(r)+"/rules", http.StatusFound)
		return
	}
	priority, _ := strconv.Atoi(r.FormValue("priority"))
	matchType := r.FormValue("match_type")
	action := r.FormValue("action")
	actionValue := strings.TrimSpace(r.FormValue("action_value"))

	conditions, ok := parseRuleConditions(r)
	if !ok || !validActions[action] {
		setFlash(w, "error", "Please fill in a valid condition and action")
		http.Redirect(w, r, Prefix+"/mailboxes/"+idStr(r)+"/rules", http.StatusFound)
		return
	}
	if action == "move_to_folder" && actionValue == "" {
		setFlash(w, "error", "Please name the folder to move matching mail into")
		http.Redirect(w, r, Prefix+"/mailboxes/"+idStr(r)+"/rules", http.StatusFound)
		return
	}
	if _, err := a.DB.CreateRuleMulti(mailbox.ID, priority, conditions, matchType, "", action, actionValue, ""); err != nil {
		setFlash(w, "error", "Error creating rule")
	} else {
		setFlash(w, "success", "Rule added")
	}
	http.Redirect(w, r, Prefix+"/mailboxes/"+idStr(r)+"/rules", http.StatusFound)
}

func (a *App) removeRule(w http.ResponseWriter, r *http.Request) {
	mailbox, ok := a.mailboxWithAccess(w, r)
	if !ok {
		return
	}
	ruleID := int64(atoi(r.PathValue("rule_id")))
	if err := a.DB.RemoveRule(ruleID, mailbox.ID); err != nil {
		setFlash(w, "error", "Error removing rule")
	} else {
		setFlash(w, "success", "Rule removed")
	}
	http.Redirect(w, r, Prefix+"/mailboxes/"+idStr(r)+"/rules", http.StatusFound)
}
