"""Tool: edit_campaign — Edit campaign name or mode after creation.

Allows changing the campaign name and switching between copilot
and autopilot modes without recreating the campaign.
"""

from __future__ import annotations

import json
import logging

from ..db.queries import (
    find_active_campaign,
    get_campaign,
    get_campaign_context,
    get_setting,
    list_campaigns,
    update_campaign,
)

logger = logging.getLogger(__name__)


async def run_edit_campaign(
    campaign_id: str = "",
    name: str = "",
    mode: str = "",
    booking_link: str = "",
    offerings: str = "",
    case_studies: str = "",
    social_proofs: str = "",
    campaign_preferences: str = "",
    voice_mode: str = "",
    voice_noise: str = "",
    voice_humanize: str = "",
) -> str:
    """Edit a campaign's name, mode, booking link, or context fields.

    Args:
        campaign_id: Which campaign to edit. Edits the first active campaign if empty.
        name: New campaign name. Leave empty to keep current name.
        mode: New mode: "copilot" or "autopilot". Leave empty to keep current mode.
        booking_link: Calendar/booking URL for positive reply auto-responses.
            Leave empty to keep current value.
        offerings: What you offer (products, services, value props). Used in follow-up messages.
        case_studies: Brief case studies or success stories. Used for social proof in messages.
        social_proofs: Social proof (logos, metrics, testimonials). Used in follow-up messages.
        campaign_preferences: Custom messaging preferences (tone, topics to avoid, etc.).
        voice_mode: Voice memo mode: "text_only", "voice_only", "mixed", or "ab_test".
            Leave empty to keep current value.
        voice_noise: Ambient noise type for voice memos: "office", "cafe", "street",
            "quiet", "none", "auto". Leave empty to keep current value.
        voice_humanize: Voice text humanization: "on" or "off".
            Leave empty to keep current value.
    """

    # ── Pre-checks ──
    setup_done = get_setting("setup_complete", False)
    if not setup_done:
        return (
            "Setup required before editing campaigns.\n\n"
            "Please run setup_profile first."
        )

    has_context_fields = any([offerings, case_studies, social_proofs, campaign_preferences])
    has_voice_settings = any([voice_noise, voice_humanize])
    if not name and not mode and not booking_link and not voice_mode and not has_context_fields and not has_voice_settings:
        return (
            "Nothing to change.\n\n"
            "Provide at least one of:\n"
            "  name: New campaign name\n"
            "  mode: \"copilot\" or \"autopilot\"\n"
            "  booking_link: Calendar URL for reply auto-responses\n"
            "  offerings: What you offer (for follow-up messages)\n"
            "  case_studies: Success stories (for social proof)\n"
            "  social_proofs: Logos, metrics, testimonials\n"
            "  campaign_preferences: Custom messaging preferences\n"
            "  voice_mode: text_only, voice_only, mixed, or ab_test\n"
            "  voice_noise: office, cafe, street, quiet, none, auto\n"
            "  voice_humanize: on or off"
        )

    # ── Validate mode ──
    if mode and mode not in ("copilot", "autopilot"):
        return (
            f"Invalid mode: '{mode}'\n\n"
            "Must be 'copilot' or 'autopilot'."
        )

    # ── Validate voice_mode ──
    if voice_mode:
        from ..constants import VALID_VOICE_MODES
        if voice_mode not in VALID_VOICE_MODES:
            return (
                f"Invalid voice_mode: '{voice_mode}'\n\n"
                "Must be one of: text_only, voice_only, mixed, ab_test"
            )

    # ── Validate voice_noise ──
    if voice_noise:
        from ..constants import VALID_NOISE_TYPES
        if voice_noise not in VALID_NOISE_TYPES:
            return (
                f"Invalid voice_noise: '{voice_noise}'\n\n"
                "Must be one of: office, cafe, street, quiet, none, auto"
            )

    # ── Validate voice_humanize ──
    if voice_humanize and voice_humanize not in ("on", "off"):
        return (
            f"Invalid voice_humanize: '{voice_humanize}'\n\n"
            "Must be 'on' or 'off'."
        )

    # ── Resolve campaign ──
    campaign, err = find_active_campaign(campaign_id)
    if not campaign and not campaign_id:
        # Fallback: try any campaign (not just active)
        campaigns = list_campaigns()
        if not campaigns:
            return (
                "No campaigns to edit.\n\n"
                "Create one first: create_campaign(\"your target description\")"
            )
        campaign = campaigns[0]
    elif not campaign:
        return err
    campaign_id = campaign["id"]

    # ── Apply changes ──
    changes: dict[str, str] = {}
    change_descriptions: list[str] = []

    old_name = campaign.get("name", "")
    old_mode = campaign.get("mode", "autopilot")

    if name and name != old_name:
        changes["name"] = name
        change_descriptions.append(f"Name: '{old_name}' -> '{name}'")

    if mode and mode != old_mode:
        changes["mode"] = mode
        change_descriptions.append(
            f"Mode: {'Copilot' if old_mode == 'copilot' else 'Autopilot'} -> "
            f"{'Copilot' if mode == 'copilot' else 'Autopilot'}"
        )

    # Parse config_json once (used by booking_link and voice_mode)
    config_json = campaign.get("config_json", "{}")
    try:
        config = json.loads(config_json) if config_json else {}
    except (json.JSONDecodeError, TypeError):
        config = {}

    if booking_link:
        old_booking = config.get("booking_link", "")
        if booking_link != old_booking:
            config["booking_link"] = booking_link
            change_descriptions.append(f"Booking link: {booking_link}")

    if voice_mode:
        old_voice = config.get("voice_mode", "text_only")
        if voice_mode != old_voice:
            config["voice_mode"] = voice_mode
            change_descriptions.append(f"Voice mode: {old_voice} -> {voice_mode}")

    if voice_noise:
        old_noise = config.get("voice_noise_type", "auto")
        if voice_noise != old_noise:
            config["voice_noise_type"] = voice_noise
            change_descriptions.append(f"Voice noise: {old_noise} -> {voice_noise}")

    if voice_humanize:
        humanize_bool = voice_humanize == "on"
        old_humanize = config.get("voice_humanize", True)
        if humanize_bool != old_humanize:
            config["voice_humanize"] = humanize_bool
            change_descriptions.append(f"Voice humanize: {'on' if old_humanize else 'off'} -> {voice_humanize}")

    # Commit config_json changes if any
    config_updated = json.dumps(config)
    if config_updated != (config_json or "{}"):
        changes["config_json"] = config_updated

    # ── Update context fields (offerings, case_studies, social_proofs, preferences) ──
    if has_context_fields:
        existing_ctx = get_campaign_context(campaign_id)
        ctx_changed = False
        if offerings:
            existing_ctx["offerings"] = offerings
            ctx_changed = True
            change_descriptions.append(f"Offerings: {offerings[:80]}{'...' if len(offerings) > 80 else ''}")
        if case_studies:
            existing_ctx["case_studies"] = case_studies
            ctx_changed = True
            change_descriptions.append(f"Case studies: {case_studies[:80]}{'...' if len(case_studies) > 80 else ''}")
        if social_proofs:
            existing_ctx["social_proofs"] = social_proofs
            ctx_changed = True
            change_descriptions.append(f"Social proofs: {social_proofs[:80]}{'...' if len(social_proofs) > 80 else ''}")
        if campaign_preferences:
            existing_ctx["campaign_preferences"] = campaign_preferences
            ctx_changed = True
            change_descriptions.append(f"Preferences: {campaign_preferences[:80]}{'...' if len(campaign_preferences) > 80 else ''}")
        if ctx_changed:
            changes["context_json"] = json.dumps(existing_ctx)

    if not changes:
        return (
            f"No changes needed for '{old_name}'.\n"
            "The campaign already has those settings."
        )

    update_campaign(campaign_id, **changes)

    # ── Format result ──
    output = [
        f"Updated campaign '{changes.get('name', old_name)}':\n",
    ]
    for desc in change_descriptions:
        output.append(f"   {desc}")
    output.append("")

    # Mode-specific hints
    if mode == "autopilot" and old_mode == "copilot":
        output.append(
            "Autopilot is now active. Messages will be sent automatically "
            "after passing validation."
        )
    elif mode == "copilot" and old_mode == "autopilot":
        output.append(
            "Copilot mode is now active. You'll review each message "
            "before it's sent."
        )

    return "\n".join(output)
