/**
 * WorkstreamActor — base class for workstream-level cognitive actors.
 *
 * Extracted from SmithersSupervisor (Phase 3 reference implementation).
 * Provides: memory persistence, plan lifecycle, context recovery on wake,
 * and a standard cognitive field pattern for any workstream.
 *
 * Typically registers with system.workstreams, but may mount anywhere in the
 * domain hierarchy. The coordinator is a registry/protocol surface, not the
 * required parent mount for every workstream instance.
 *
 * Subclasses declare:
 *   - static purpose (required)
 *   - static systemPrompt (optional)
 *   - static promptTriggers (optional)
 *   - static skills (optional)
 *   - onBootstrap(): initialize domain-specific state
 *
 * Constraints satisfied:
 *   C14: One actor per workstream
 *   C16: Memory survives context window death
 *   C17: Extracted from proven Smithers pattern
 */
import { MatrixActor } from './MatrixActor';
import { RequestReply } from '../engine/remoting/RequestReply';

/** Plan step structure */
export interface PlanStep {
  name: string;
  status: 'pending' | 'in_progress' | 'completed' | 'failed' | 'skipped';
}

/** Active plan recovered from memory */
export interface ActivePlan {
  planId?: string;
  name: string;
  steps: PlanStep[];
}

interface WorkstreamRequestRecord {
  id: string;
  text: string;
  from: string | null;
  priority: string | null;
  status: 'pending';
  ts: number;
}

/**
 * Base class for workstream actors. Extends MatrixActor with
 * memory persistence, plan lifecycle, and context recovery.
 */
export class WorkstreamActor extends MatrixActor {
  // ─── Cognitive Defaults ──────────────────────────────────────────────
  // Subclasses MUST override purpose. All other fields have sensible defaults.

  static promptable = true;
  static regime = 'focused' as const;
  static memoryScope = 'actor' as const;
  static planScope = 'actor' as const;
  static continuationType = 'persistent' as const;
  static kind = 'workstream';

  static contract = {
    interfaces: {
      workstream: {
        description: 'Generic durable workstream actor surface',
        ops: {
          status: {
            description: 'Get workstream status summary',
            payload: {},
            response: {
              ok: { type: 'boolean', required: true },
              name: { type: 'string', required: true },
              purpose: { type: 'string', required: true },
              regime: { type: 'string', required: true },
              promptable: { type: 'boolean', required: true },
              pendingRequests: { type: 'number', required: true },
              activeAgentCount: { type: 'number', required: true },
            },
          },
          request: {
            description: 'Submit an external request into the workstream inbox',
            payload: {
              text: { type: 'string', required: true, description: 'Request text or instruction' },
              from: { type: 'string', required: false, description: 'Requesting actor or operator' },
              priority: { type: 'string', required: false, description: 'Optional priority label' },
            },
            response: {
              ok: { type: 'boolean', required: true },
              requestId: { type: 'string', required: true },
              status: { type: 'string', required: true },
            },
          },
          plan: {
            description: 'Get active plan',
            payload: {},
            response: {
              ok: { type: 'boolean', required: true },
              plan: { type: 'object', required: false, description: 'Active plan when present' },
            },
          },
          agents: {
            description: 'List the workstream actor and visible child agents',
            payload: {},
            response: {
              ok: { type: 'boolean', required: true },
              agents: { type: 'array', required: true },
            },
          },
        },
      },
    },
  };

  static accepts = {
    'workstream.status': { description: 'Get workstream status summary' },
    'workstream.request': { description: 'Submit a request into the workstream inbox' },
    'workstream.memory': { description: 'Query workstream memory' },
    'workstream.plan': { description: 'Get active plan' },
    'workstream.agents': { description: 'List the workstream actor and visible child agents' },
  };

  static emits = {
    'workstream.phaseChanged': { description: 'Published when workstream phase changes' },
    'workstream.memoryWritten': { description: 'Published when a memory record is saved' },
    'workstream.requested': { description: 'Published when a new workstream request is queued' },
  };

  // ─── Instance State ──────────────────────────────────────────────────

  /** Active plan recovered from memory on wake */
  protected _activePlan: ActivePlan | null = null;
  /** Workstream name (derived from mount path) */
  protected _workstreamName = '';
  /** Minimal in-memory request inbox for generic operator tooling */
  protected _requests: WorkstreamRequestRecord[] = [];
  /** Best-effort flag to avoid unregister spam when registration never succeeded */
  protected _registeredWithCoordinator = false;

  // ─── Lifecycle ───────────────────────────────────────────────────────

  protected override async onBootstrap(): Promise<void> {
    // Derive workstream name from the actor mount, regardless of namespace.
    const mount = this._context?.mount ?? '';
    const parts = mount.split('.');
    this._workstreamName = parts[parts.length - 1] || 'unknown';

    // Phase 3/C16: Recover context from memory on wake
    await this._recoverFromMemory();
    await this._registerWithCoordinator();
  }

  protected override onDispose(): void {
    this._unregisterFromCoordinator();
  }

  /** Recover active plan and recent memory on actor wake. */
  private async _recoverFromMemory(): Promise<void> {
    try {
      const plan = await this.queryActivePlan();
      if (plan) {
        this._activePlan = plan;
        const currentStep = plan.steps.findIndex(s => s.status === 'in_progress');
        // eslint-disable-next-line no-console -- bootstrap recovery notice for kernel workstream actor
        console.log(`[${this._workstreamName}] Recovered active plan: ${plan.name}, step ${currentStep + 1}/${plan.steps.length}`);
      }
    } catch { /* memory service may not be ready at bootstrap — non-fatal */ }
  }

  // ─── Op Handlers ─────────────────────────────────────────────────────

  onWorkstreamStatus(): unknown {
    const ctor = this.constructor as typeof WorkstreamActor;
    const childCount = this._children?.getAllChildren()?.length ?? 0;
    return {
      ok: true,
      name: this._workstreamName,
      purpose: ctor.purpose ?? '(none)',
      regime: ctor.regime,
      promptable: ctor.promptable,
      kind: ctor.kind,
      pendingRequests: this._requests.length,
      activeAgentCount: 1 + childCount,
      activePlan: this._activePlan ? {
        name: this._activePlan.name,
        steps: this._activePlan.steps,
        currentStep: this._activePlan.steps.find(s => s.status === 'in_progress')?.name ?? null,
      } : null,
      triggers: ctor.promptTriggers?.length ?? 0,
    };
  }

  onWorkstreamRequest(payload: Record<string, unknown>): unknown {
    const text = typeof payload.text === 'string' ? payload.text.trim() : '';
    if (!text) return { ok: false, error: 'text required' };

    const request: WorkstreamRequestRecord = {
      id: `req-${Date.now()}-${this._requests.length + 1}`,
      text,
      from: typeof payload.from === 'string' ? payload.from : null,
      priority: typeof payload.priority === 'string' ? payload.priority : null,
      status: 'pending',
      ts: Date.now(),
    };
    this._requests.push(request);
    this.emit('workstream.requested', request);
    return { ok: true, requestId: request.id, status: request.status };
  }

  private async _registerWithCoordinator(): Promise<void> {
    if (!this._context) return;
    const ctor = this.constructor as typeof WorkstreamActor;
    try {
      await RequestReply.execute(this._context, 'system.workstreams', 'workstream.register', {
        name: this._workstreamName,
        mount: this._context.mount,
        type: ctor.name,
        purpose: ctor.purpose ?? '(none)',
        promptable: ctor.promptable,
        regime: ctor.regime,
        triggerCount: ctor.promptTriggers?.length ?? 0,
      }, { timeoutMs: 2000 });
      this._registeredWithCoordinator = true;
    } catch {
      this._registeredWithCoordinator = false;
    }
  }

  private _unregisterFromCoordinator(): void {
    if (!this._context || !this._registeredWithCoordinator) return;
    RequestReply.execute(this._context, 'system.workstreams', 'workstream.unregister', {
      mount: this._context.mount,
    }, { timeoutMs: 1000 }).catch(() => {});
  }

  async onWorkstreamMemory(payload: Record<string, unknown>): Promise<unknown> {
    const limit = typeof payload.limit === 'number' ? payload.limit : 10;
    return this.queryRecentMemory(limit);
  }

  async onWorkstreamPlan(): Promise<unknown> {
    const plan = this._activePlan ?? await this.queryActivePlan();
    return plan ? { ok: true, plan } : { ok: false, error: 'No active plan' };
  }

  onWorkstreamAgents(): unknown {
    const childAgents = (this._children?.getAllChildren() ?? []).map((child) => ({
      id: child.id,
      mount: child.mount,
      componentClass: child.componentClass,
      role: 'child',
    }));

    return {
      ok: true,
      agents: [
        {
          id: this._workstreamName,
          mount: this._context?.mount ?? '',
          componentClass: (this.constructor as typeof WorkstreamActor).name,
          role: 'workstream',
        },
        ...childAgents,
      ],
    };
  }

  // ─── Memory Helpers (protected — available to subclasses) ────────────

  /** Save a memory record at a key decision point. Non-fatal on failure. */
  protected async saveMemory(content: string, tags: string[] = []): Promise<void> {
    if (!this._context) return;
    try {
      await RequestReply.execute(this._context, 'system.agents.memory', 'memory.save', {
        mount: this._context.mount,
        content,
        tags: [this._workstreamName, ...tags],
      }, { timeoutMs: 5000 });
      this.emit('workstream.memoryWritten', { content: content.slice(0, 100), tags });
      // Stigmergy: publish workstream state to blackboard
      RequestReply.sendToInbox(this._context, 'system.blackboard', 'fact.assert', {
        domain: `workstream.${this._workstreamName}`,
        data: { lastMemory: content.slice(0, 100), tags, updatedAt: Date.now() },
      });
    } catch { /* memory service may be unavailable — non-fatal */ }
  }

  /** Query active plan from system.memory. */
  protected async queryActivePlan(): Promise<ActivePlan | null> {
    if (!this._context) return null;
    try {
      const result = await RequestReply.execute(this._context, 'system.agents.memory', 'plan.active', {
        mount: this._context.mount,
      }, { timeoutMs: 3000 }) as Record<string, unknown>;
      if (result?.ok && result?.name) {
        return result as unknown as ActivePlan;
      }
    } catch { /* memory service unavailable */ }
    return null;
  }

  /** Query recent memory records. */
  protected async queryRecentMemory(limit = 10): Promise<unknown> {
    if (!this._context) return { ok: false, error: 'No context' };
    try {
      return await RequestReply.execute(this._context, 'system.agents.memory', 'memory.history', {
        mount: this._context.mount, limit,
      }, { timeoutMs: 3000 });
    } catch { return { ok: false, error: 'Memory service unavailable' }; }
  }

  // ─── Plan Lifecycle (protected — available to subclasses) ────────────

  /** Create a plan with named steps. Returns planId or null. */
  protected async createPlan(name: string, steps: Array<{ name: string }>): Promise<string | null> {
    if (!this._context) return null;
    try {
      const result = await RequestReply.execute(this._context, 'system.agents.memory', 'plan.create', {
        mount: this._context.mount,
        name,
        steps: steps.map(s => ({ name: s.name, status: 'pending' })),
      }, { timeoutMs: 5000 }) as Record<string, unknown>;
      const planId = (result?.planId as string) ?? null;
      if (planId && result?.name) {
        this._activePlan = result as unknown as ActivePlan;
      }
      return planId;
    } catch { return null; }
  }

  /** Update a plan step status. */
  protected async updatePlanStep(planId: string, stepIndex: number, status: string): Promise<void> {
    if (!this._context) return;
    try {
      await RequestReply.execute(this._context, 'system.agents.memory', 'plan.update', {
        planId, stepIndex, status,
      }, { timeoutMs: 3000 });
      // Update local cache
      if (this._activePlan?.planId === planId && this._activePlan.steps[stepIndex]) {
        this._activePlan.steps[stepIndex].status = status as PlanStep['status'];
      }
      this.emit('workstream.phaseChanged', { planId, stepIndex, status });
    } catch { /* non-fatal */ }
  }

  /** Mark a plan as complete. */
  protected async completePlan(planId: string): Promise<void> {
    if (!this._context) return;
    try {
      await RequestReply.execute(this._context, 'system.agents.memory', 'plan.complete', {
        planId,
      }, { timeoutMs: 3000 });
      if (this._activePlan?.planId === planId) {
        this._activePlan = null; // Clear active plan
      }
    } catch { /* non-fatal */ }
  }
}
