/**
 * User Profile Tests
 *
 * Scenarios covering user profiles: published trails, completed trails,
 * and how activity affects what's shown.
 */

import { describe, it, expect } from "vitest";
import * as queries from "../queries";
import { emit, emitDelete, ALICE, BOB, CAROL, generateTid } from "./helpers";

const now = () => new Date().toISOString();

describe("Viewing a user's published trails", () => {
  it("shows all trails created by the user", async () => {
    await emit("app.sidetrail.trail", ALICE.did, {
      $type: "app.sidetrail.trail",
      title: "Alice's First Trail",
      description: "Her debut",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#ff0000",
      backgroundColor: "#ffffff",
      createdAt: now(),
    });

    await emit("app.sidetrail.trail", ALICE.did, {
      $type: "app.sidetrail.trail",
      title: "Alice's Second Trail",
      description: "Another one",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#00ff00",
      backgroundColor: "#f0f0f0",
      createdAt: now(),
    });

    const publishedTrails = await queries.loadUserPublishedTrails(ALICE.handle);
    expect(publishedTrails).toHaveLength(2);
  });

  it("orders published trails by createdAt descending", async () => {
    await emit("app.sidetrail.trail", ALICE.did, {
      $type: "app.sidetrail.trail",
      title: "Old Trail",
      description: "First",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#111",
      backgroundColor: "#eee",
      createdAt: "2024-01-01T10:00:00Z",
    });

    await emit("app.sidetrail.trail", ALICE.did, {
      $type: "app.sidetrail.trail",
      title: "New Trail",
      description: "Last",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#222",
      backgroundColor: "#ddd",
      createdAt: "2024-06-01T10:00:00Z",
    });

    const publishedTrails = await queries.loadUserPublishedTrails(ALICE.handle);
    expect(publishedTrails[0].title).toBe("New Trail");
    expect(publishedTrails[1].title).toBe("Old Trail");
  });

  it("published trail cards show active walkers", async () => {
    const stopTid = generateTid();
    const trail = await emit("app.sidetrail.trail", ALICE.did, {
      $type: "app.sidetrail.trail",
      title: "Popular Trail",
      description: "Many walkers",
      stops: [{ tid: stopTid, title: "Stop", content: "Content" }],
      accentColor: "#333",
      backgroundColor: "#ccc",
      createdAt: now(),
    });

    await emit("app.sidetrail.walk", BOB.did, {
      $type: "app.sidetrail.walk",
      trail: { uri: trail.uri, cid: trail.cid },
      visitedStops: [stopTid],
      createdAt: now(),
      updatedAt: now(),
    });

    const publishedTrails = await queries.loadUserPublishedTrails(ALICE.handle);
    const activeWalkers = await queries.loadTrailActiveWalkers(publishedTrails[0].uri);
    expect(activeWalkers).toHaveLength(1);
    expect(activeWalkers[0].handle).toBe(BOB.handle);
  });

  it("does not show other users' trails", async () => {
    await emit("app.sidetrail.trail", ALICE.did, {
      $type: "app.sidetrail.trail",
      title: "Alice's Trail",
      description: "By Alice",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#aaa",
      backgroundColor: "#bbb",
      createdAt: now(),
    });

    await emit("app.sidetrail.trail", BOB.did, {
      $type: "app.sidetrail.trail",
      title: "Bob's Trail",
      description: "By Bob",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#ccc",
      backgroundColor: "#ddd",
      createdAt: now(),
    });

    const aliceTrails = await queries.loadUserPublishedTrails(ALICE.handle);
    expect(aliceTrails).toHaveLength(1);
    expect(aliceTrails[0].title).toBe("Alice's Trail");

    const bobTrails = await queries.loadUserPublishedTrails(BOB.handle);
    expect(bobTrails).toHaveLength(1);
    expect(bobTrails[0].title).toBe("Bob's Trail");
  });
});

describe("Viewing a user's completed trails", () => {
  it("shows trails the user has completed", async () => {
    const trail = await emit("app.sidetrail.trail", ALICE.did, {
      $type: "app.sidetrail.trail",
      title: "Completable Trail",
      description: "Finish this",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#ff0000",
      backgroundColor: "#ffffff",
      createdAt: now(),
    });

    await emit("app.sidetrail.completion", BOB.did, {
      $type: "app.sidetrail.completion",
      trail: { uri: trail.uri, cid: trail.cid },
      createdAt: now(),
    });

    const completedTrails = await queries.loadUserCompletedTrails(BOB.handle);
    expect(completedTrails).toHaveLength(1);
    expect(completedTrails[0].title).toBe("Completable Trail");
    expect(completedTrails[0].creator.handle).toBe(ALICE.handle);
  });

  it("orders completed trails by completion date descending", async () => {
    const trail1 = await emit("app.sidetrail.trail", ALICE.did, {
      $type: "app.sidetrail.trail",
      title: "First Completed",
      description: "Test",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#111",
      backgroundColor: "#eee",
      createdAt: now(),
    });

    const trail2 = await emit("app.sidetrail.trail", ALICE.did, {
      $type: "app.sidetrail.trail",
      title: "Last Completed",
      description: "Test",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#222",
      backgroundColor: "#ddd",
      createdAt: now(),
    });

    await emit("app.sidetrail.completion", BOB.did, {
      $type: "app.sidetrail.completion",
      trail: { uri: trail1.uri, cid: trail1.cid },
      createdAt: "2024-01-01T10:00:00Z",
    });

    await emit("app.sidetrail.completion", BOB.did, {
      $type: "app.sidetrail.completion",
      trail: { uri: trail2.uri, cid: trail2.cid },
      createdAt: "2024-06-01T10:00:00Z",
    });

    const completedTrails = await queries.loadUserCompletedTrails(BOB.handle);
    expect(completedTrails[0].title).toBe("Last Completed");
    expect(completedTrails[1].title).toBe("First Completed");
  });

  it("dedupes multiple completions of same trail (shows most recent)", async () => {
    const trail = await emit("app.sidetrail.trail", ALICE.did, {
      $type: "app.sidetrail.trail",
      title: "Re-completable",
      description: "Completed twice",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#333",
      backgroundColor: "#ccc",
      createdAt: now(),
    });

    // First completion
    await emit("app.sidetrail.completion", BOB.did, {
      $type: "app.sidetrail.completion",
      trail: { uri: trail.uri, cid: trail.cid },
      createdAt: "2024-01-01T10:00:00Z",
    });

    // Second completion (newer)
    await emit("app.sidetrail.completion", BOB.did, {
      $type: "app.sidetrail.completion",
      trail: { uri: trail.uri, cid: trail.cid },
      createdAt: "2024-06-01T10:00:00Z",
    });

    const completedTrails = await queries.loadUserCompletedTrails(BOB.handle);
    expect(completedTrails).toHaveLength(1);
    expect(completedTrails[0].completedAt.toISOString()).toBe("2024-06-01T10:00:00.000Z");
  });

  it("excludes completions where trail was deleted", async () => {
    const trail = await emit("app.sidetrail.trail", ALICE.did, {
      $type: "app.sidetrail.trail",
      title: "Soon Deleted",
      description: "Will be orphaned",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#444",
      backgroundColor: "#bbb",
      createdAt: now(),
    });

    await emit("app.sidetrail.completion", BOB.did, {
      $type: "app.sidetrail.completion",
      trail: { uri: trail.uri, cid: trail.cid },
      createdAt: now(),
    });

    let completedTrails = await queries.loadUserCompletedTrails(BOB.handle);
    expect(completedTrails).toHaveLength(1);

    // Trail gets deleted
    await emitDelete("app.sidetrail.trail", trail.uri);

    completedTrails = await queries.loadUserCompletedTrails(BOB.handle);
    expect(completedTrails).toHaveLength(0);
  });
});

describe("Profile showing both published and completed", () => {
  it("user can have both published and completed trails", async () => {
    // Alice publishes a trail
    await emit("app.sidetrail.trail", ALICE.did, {
      $type: "app.sidetrail.trail",
      title: "Alice's Published Trail",
      description: "Created by Alice",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#ff0000",
      backgroundColor: "#ffffff",
      createdAt: now(),
    });

    // Bob publishes a trail
    const bobTrail = await emit("app.sidetrail.trail", BOB.did, {
      $type: "app.sidetrail.trail",
      title: "Bob's Trail",
      description: "Created by Bob",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#00ff00",
      backgroundColor: "#f0f0f0",
      createdAt: now(),
    });

    // Alice completes Bob's trail
    await emit("app.sidetrail.completion", ALICE.did, {
      $type: "app.sidetrail.completion",
      trail: { uri: bobTrail.uri, cid: bobTrail.cid },
      createdAt: now(),
    });

    const publishedTrails = await queries.loadUserPublishedTrails(ALICE.handle);
    expect(publishedTrails).toHaveLength(1);
    expect(publishedTrails[0].title).toBe("Alice's Published Trail");

    const completedTrails = await queries.loadUserCompletedTrails(ALICE.handle);
    expect(completedTrails).toHaveLength(1);
    expect(completedTrails[0].title).toBe("Bob's Trail");
  });
});

describe("Deleting a completion", () => {
  it("removes completion from user's profile", async () => {
    const trail = await emit("app.sidetrail.trail", ALICE.did, {
      $type: "app.sidetrail.trail",
      title: "Uncomplete Trail",
      description: "Remove completion",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#555",
      backgroundColor: "#aaa",
      createdAt: now(),
    });

    const completion = await emit("app.sidetrail.completion", BOB.did, {
      $type: "app.sidetrail.completion",
      trail: { uri: trail.uri, cid: trail.cid },
      createdAt: now(),
    });

    let completedTrails = await queries.loadUserCompletedTrails(BOB.handle);
    expect(completedTrails).toHaveLength(1);

    await emitDelete("app.sidetrail.completion", completion.uri);

    completedTrails = await queries.loadUserCompletedTrails(BOB.handle);
    expect(completedTrails).toHaveLength(0);
  });
});

describe("Empty profile states", () => {
  it("user with no activity has empty lists", async () => {
    const publishedTrails = await queries.loadUserPublishedTrails(ALICE.handle);
    const completedTrails = await queries.loadUserCompletedTrails(ALICE.handle);
    expect(publishedTrails).toHaveLength(0);
    expect(completedTrails).toHaveLength(0);
  });
});

describe("Profile trail deletion cascade", () => {
  it("deleting a trail removes it from author's published trails", async () => {
    const trail = await emit("app.sidetrail.trail", ALICE.did, {
      $type: "app.sidetrail.trail",
      title: "Ephemeral Trail",
      description: "Will be deleted",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#666",
      backgroundColor: "#999",
      createdAt: now(),
    });

    let publishedTrails = await queries.loadUserPublishedTrails(ALICE.handle);
    expect(publishedTrails).toHaveLength(1);

    await emitDelete("app.sidetrail.trail", trail.uri);

    publishedTrails = await queries.loadUserPublishedTrails(ALICE.handle);
    expect(publishedTrails).toHaveLength(0);
  });
});

describe("Profile with multiple completers", () => {
  it("each user's profile shows their own completions", async () => {
    const trail = await emit("app.sidetrail.trail", ALICE.did, {
      $type: "app.sidetrail.trail",
      title: "Popular Trail",
      description: "Many completers",
      stops: [{ tid: generateTid(), title: "Stop", content: "Content" }],
      accentColor: "#777",
      backgroundColor: "#888",
      createdAt: now(),
    });

    await emit("app.sidetrail.completion", BOB.did, {
      $type: "app.sidetrail.completion",
      trail: { uri: trail.uri, cid: trail.cid },
      createdAt: now(),
    });

    await emit("app.sidetrail.completion", CAROL.did, {
      $type: "app.sidetrail.completion",
      trail: { uri: trail.uri, cid: trail.cid },
      createdAt: now(),
    });

    const bobCompleted = await queries.loadUserCompletedTrails(BOB.handle);
    expect(bobCompleted).toHaveLength(1);

    const carolCompleted = await queries.loadUserCompletedTrails(CAROL.handle);
    expect(carolCompleted).toHaveLength(1);

    // Alice (author) has no completions
    const aliceCompleted = await queries.loadUserCompletedTrails(ALICE.handle);
    expect(aliceCompleted).toHaveLength(0);

    const alicePublished = await queries.loadUserPublishedTrails(ALICE.handle);
    expect(alicePublished).toHaveLength(1);
  });
});
