import { LitElement, html, css } from "lit";

/**
 * SkillTreeUI.js
 * Interactive skill tree component with CSS 3D voxel nodes and SVG connections.
 * Renders the progression tree for an Explorer unit.
 */
export class SkillTreeUI extends LitElement {
  static get styles() {
    return css`
      :host {
        display: block;
        width: 100%;
        height: 100%;
        min-height: 0; /* Allow host to shrink */
        max-height: 100%; /* Constrain to parent */
        position: relative;
      }

      .tree-container {
        width: 100%;
        height: 100%;
        min-height: 0; /* Allow container to shrink */
        max-height: 100%; /* Constrain to parent */
        overflow-y: auto;
        overflow-x: hidden;
        position: relative;
        background: rgba(0, 0, 0, 0.3);
      }

      .tree-content {
        position: relative;
        min-height: 100%;
        padding: 40px 20px;
        display: flex;
        flex-direction: column-reverse;
        gap: 60px;
      }

      .tier-row {
        display: flex;
        justify-content: center;
        align-items: center;
        gap: 40px;
        flex-wrap: wrap;
        min-height: 120px;
        position: relative;
      }

      .tier-label {
        position: absolute;
        left: 10px;
        top: 50%;
        transform: translateY(-50%);
        font-size: 14px;
        color: #888;
        font-weight: bold;
        writing-mode: vertical-rl;
        text-orientation: mixed;
      }

      /* SVG Connections Overlay */
      .connections-overlay {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        pointer-events: none;
        z-index: 1;
      }

      .connection-line {
        fill: none;
        stroke-width: 2;
        transition: stroke 0.3s;
      }

      .connection-line.unlocked {
        stroke: #00ffff;
        filter: drop-shadow(0 0 3px rgba(0, 255, 255, 0.5));
      }

      .connection-line.available {
        stroke: #666;
        opacity: 0.5;
      }

      .connection-line.locked {
        stroke: #333;
        opacity: 0.3;
      }

      /* Voxel Node */
      .voxel-node {
        position: relative;
        width: 80px;
        height: 80px;
        transform-style: preserve-3d;
        cursor: pointer;
        z-index: 2;
      }

      .voxel-cube {
        width: 100%;
        height: 100%;
        position: relative;
        transform-style: preserve-3d;
      }

      /* Cube Faces */
      .cube-face {
        position: absolute;
        width: 80px;
        height: 80px;
        border: 2px solid rgba(255, 255, 255, 0.3);
        display: flex;
        align-items: center;
        justify-content: center;
        backface-visibility: hidden;
      }

      .cube-face.front {
        transform: translateZ(40px);
      }

      .cube-face.back {
        transform: rotateY(180deg) translateZ(40px);
      }

      .cube-face.right {
        transform: rotateY(90deg) translateZ(40px);
      }

      .cube-face.left {
        transform: rotateY(-90deg) translateZ(40px);
      }

      .cube-face.top {
        transform: rotateX(90deg) translateZ(40px);
      }

      .cube-face.bottom {
        transform: rotateX(-90deg) translateZ(40px);
      }

      /* Node States */
      .voxel-node.locked .cube-face {
        background: rgba(50, 50, 50, 0.8);
        border-color: #444;
      }

      .voxel-node.available .cube-face {
        background: rgba(0, 100, 200, 0.6);
        border-color: #00aaff;
        animation: pulse-available 2s ease-in-out infinite;
      }

      .voxel-node.unlocked .cube-face {
        background: rgba(0, 200, 255, 0.8);
        border-color: #00ffff;
        box-shadow: 0 0 15px rgba(0, 255, 255, 0.6);
        animation: rotate-unlocked 8s linear infinite;
      }

      .voxel-node.unlocked .voxel-cube {
        animation: rotate-unlocked 8s linear infinite;
      }

      @keyframes pulse-available {
        0%,
        100% {
          transform: translateY(0);
          opacity: 0.6;
        }
        50% {
          transform: translateY(-5px);
          opacity: 0.9;
        }
      }

      @keyframes rotate-unlocked {
        from {
          transform: rotateY(0deg) rotateX(0deg);
        }
        to {
          transform: rotateY(360deg) rotateX(15deg);
        }
      }

      .node-icon {
        font-size: 32px;
        color: white;
        text-shadow: 0 0 5px rgba(0, 0, 0, 0.8);
      }

      .node-icon img {
        width: 48px;
        height: 48px;
        object-fit: contain;
      }

      /* Inspector Footer */
      .inspector {
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        background: rgba(10, 10, 20, 0.95);
        border-top: 3px solid #00ffff;
        padding: 20px;
        transform: translateY(100%);
        transition: transform 0.3s ease-out;
        z-index: 1000;
        max-height: 200px;
        overflow-y: auto;
      }

      .inspector.visible {
        transform: translateY(0);
      }

      .inspector-content {
        display: flex;
        flex-direction: column;
        gap: 15px;
        max-width: 800px;
        margin: 0 auto;
      }

      .inspector-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
      }

      .inspector-title {
        font-size: 20px;
        font-weight: bold;
        color: #00ffff;
        margin: 0;
      }

      .inspector-close {
        background: transparent;
        border: 2px solid #ff6666;
        color: #ff6666;
        width: 30px;
        height: 30px;
        cursor: pointer;
        font-size: 18px;
        display: flex;
        align-items: center;
        justify-content: center;
      }

      .inspector-close:hover {
        background: #ff6666;
        color: white;
      }

      .inspector-description {
        color: #aaa;
        font-size: 14px;
        margin: 0;
      }

      .inspector-requirements {
        display: flex;
        flex-direction: column;
        gap: 5px;
        font-size: 12px;
        color: #888;
      }

      .unlock-button {
        background: #00ff00;
        color: #000;
        border: none;
        padding: 12px 24px;
        font-size: 16px;
        font-weight: bold;
        cursor: pointer;
        transition: all 0.2s;
        font-family: inherit;
      }

      .unlock-button:hover:not(:disabled) {
        background: #00cc00;
        transform: scale(1.05);
      }

      .unlock-button:disabled {
        background: #666;
        color: #999;
        cursor: not-allowed;
      }

      .error-message {
        color: #ff6666;
        font-size: 12px;
        margin-top: 5px;
      }
    `;
  }

  static get properties() {
    return {
      unit: { type: Object },
      treeDef: { type: Object },
      selectedNodeId: { type: String },
      updateTrigger: { type: Number }, // Triggers update when unlocked nodes change
    };
  }

  constructor() {
    super();
    this.unit = null;
    this.treeDef = null;
    this.selectedNodeId = null;
    this.updateTrigger = 0;
    this.nodeRefs = new Map();
    this.resizeObserver = null;
    this.connectionPaths = [];
  }

  connectedCallback() {
    super.connectedCallback();
    this._setupResizeObserver();
    this._scrollToAvailableTier();
  }

  disconnectedCallback() {
    super.disconnectedCallback();
    if (this.resizeObserver) {
      this.resizeObserver.disconnect();
    }
  }

  updated(changedProperties) {
    super.updated(changedProperties);
    if (
      changedProperties.has("unit") ||
      changedProperties.has("treeDef") ||
      changedProperties.has("updateTrigger")
    ) {
      this._updateConnections();
      this._scrollToAvailableTier();
    }
    if (changedProperties.has("selectedNodeId")) {
      this._updateConnections();
    }
  }

  firstUpdated() {
    this._updateConnections();
    this._scrollToAvailableTier();
  }

  /**
   * Sets up ResizeObserver to track node positions for connection lines
   */
  _setupResizeObserver() {
    if (typeof ResizeObserver === "undefined") {
      return;
    }

    this.resizeObserver = new ResizeObserver(() => {
      this._updateConnections();
    });

    // Observe the tree container
    const container = this.shadowRoot?.querySelector(".tree-container");
    if (container) {
      this.resizeObserver.observe(container);
    }
  }

  /**
   * Gets or creates a simple tree definition from unit
   * @returns {Object}
   */
  _getTreeDefinition() {
    if (this.treeDef) {
      return this.treeDef;
    }

    if (!this.unit) {
      return null;
    }

    // Create a simple mock tree for demonstration
    // In production, this would come from SkillTreeFactory
    return {
      id: `TREE_${this.unit.activeClassId}`,
      nodes: {
        ROOT: {
          id: "ROOT",
          tier: 1,
          type: "STAT_BOOST",
          children: ["NODE_1", "NODE_2"],
          data: { stat: "health", value: 10 },
          req: 1,
          cost: 1,
        },
        NODE_1: {
          id: "NODE_1",
          tier: 2,
          type: "ACTIVE_SKILL",
          children: ["NODE_3"],
          data: { name: "Shield Bash", id: "SKILL_SHIELD_BASH" },
          req: 2,
          cost: 1,
        },
        NODE_2: {
          id: "NODE_2",
          tier: 2,
          type: "STAT_BOOST",
          children: [],
          data: { stat: "defense", value: 5 },
          req: 2,
          cost: 1,
        },
        NODE_3: {
          id: "NODE_3",
          tier: 3,
          type: "PASSIVE_ABILITY",
          children: [],
          data: { name: "Iron Skin", id: "PASSIVE_IRON_SKIN" },
          req: 3,
          cost: 2,
        },
      },
    };
  }

  /**
   * Calculates node status: LOCKED, AVAILABLE, or UNLOCKED
   * @param {string} nodeId - Node ID
   * @param {Object} nodeDef - Node definition
   * @returns {string}
   */
  _calculateNodeStatus(nodeId, nodeDef) {
    if (!this.unit || !this.unit.classMastery) {
      return "LOCKED";
    }

    const mastery = this.unit.classMastery[this.unit.activeClassId];
    if (!mastery) {
      return "LOCKED";
    }

    // Check if unlocked
    if (mastery.unlockedNodes && mastery.unlockedNodes.includes(nodeId)) {
      return "UNLOCKED";
    }

    // Check if available (parent unlocked and level requirement met)
    const unitLevel = mastery.level || 1;
    const levelReq = nodeDef.req || 1;

    // Find parent nodes
    const parentNodes = this._findParentNodes(nodeId);
    const hasUnlockedParent =
      parentNodes.length === 0 ||
      parentNodes.some((parentId) => mastery.unlockedNodes?.includes(parentId));

    if (hasUnlockedParent && unitLevel >= levelReq) {
      return "AVAILABLE";
    }

    return "LOCKED";
  }

  /**
   * Finds parent nodes for a given node
   * @param {string} nodeId - Node ID
   * @returns {string[]}
   */
  _findParentNodes(nodeId) {
    const tree = this._getTreeDefinition();
    if (!tree) return [];

    const parents = [];
    for (const [id, node] of Object.entries(tree.nodes)) {
      if (node.children && node.children.includes(nodeId)) {
        parents.push(id);
      }
    }
    return parents;
  }

  /**
   * Updates SVG connection lines between nodes
   */
  _updateConnections() {
    const tree = this._getTreeDefinition();
    if (!tree) return;

    const svgContainer = this.shadowRoot?.querySelector(".connections-overlay");
    if (!svgContainer) return;

    let svg = svgContainer.querySelector("svg");
    if (!svg) {
      svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
      svg.setAttribute("width", "100%");
      svg.setAttribute("height", "100%");
      svgContainer.appendChild(svg);
    }

    const container = this.shadowRoot?.querySelector(".tree-container");
    if (!container) return;

    const containerRect = container.getBoundingClientRect();
    const paths = [];

    // Clear existing paths
    svg.innerHTML = "";

    // Draw connections for each node
    for (const [nodeId, nodeDef] of Object.entries(tree.nodes)) {
      if (!nodeDef.children || nodeDef.children.length === 0) continue;

      const parentElement = this.shadowRoot?.querySelector(
        `[data-node-id="${nodeId}"]`
      );
      if (!parentElement) continue;

      const parentRect = parentElement.getBoundingClientRect();
      const parentCenter = {
        x: parentRect.left + parentRect.width / 2 - containerRect.left,
        y: parentRect.top + parentRect.height / 2 - containerRect.top,
      };

      for (const childId of nodeDef.children) {
        const childElement = this.shadowRoot?.querySelector(
          `[data-node-id="${childId}"]`
        );
        if (!childElement) continue;

        const childRect = childElement.getBoundingClientRect();
        const childCenter = {
          x: childRect.left + childRect.width / 2 - containerRect.left,
          y: childRect.top + childRect.height / 2 - containerRect.top,
        };

        // Determine line style based on child status
        const childStatus = this._calculateNodeStatus(
          childId,
          tree.nodes[childId]
        );
        const pathClass = `connection-line ${childStatus.toLowerCase()}`;

        // Create path with 90-degree bends (circuit board style)
        const midX = parentCenter.x;
        const midY = childCenter.y;
        const pathData = `M ${parentCenter.x} ${parentCenter.y} L ${midX} ${parentCenter.y} L ${midX} ${midY} L ${childCenter.x} ${midY} L ${childCenter.x} ${childCenter.y}`;

        const path = document.createElementNS(
          "http://www.w3.org/2000/svg",
          "path"
        );
        path.setAttribute("d", pathData);
        path.setAttribute("class", pathClass);
        svg.appendChild(path);
      }
    }
  }

  /**
   * Scrolls to the highest tier with an available node
   */
  _scrollToAvailableTier() {
    const tree = this._getTreeDefinition();
    if (!tree || !this.unit) return;

    // Find highest tier with available nodes
    let highestTier = 0;
    let targetElement = null;

    for (const [nodeId, nodeDef] of Object.entries(tree.nodes)) {
      const status = this._calculateNodeStatus(nodeId, nodeDef);
      if (status === "AVAILABLE" && nodeDef.tier > highestTier) {
        highestTier = nodeDef.tier;
        const element = this.shadowRoot?.querySelector(
          `[data-node-id="${nodeId}"]`
        );
        if (element) {
          targetElement = element;
        }
      }
    }

    if (targetElement) {
      setTimeout(() => {
        targetElement.scrollIntoView({ behavior: "smooth", block: "center" });
      }, 100);
    }
  }

  /**
   * Handles node click
   * @param {string} nodeId - Node ID
   */
  _handleNodeClick(nodeId) {
    this.selectedNodeId = nodeId;
    this.requestUpdate();
  }

  /**
   * Handles unlock button click
   */
  _handleUnlock() {
    if (!this.selectedNodeId) return;

    const tree = this._getTreeDefinition();
    if (!tree) return;

    const nodeDef = tree.nodes[this.selectedNodeId];
    if (!nodeDef) return;

    const cost = nodeDef.cost || 1;

    // Dispatch unlock request event
    this.dispatchEvent(
      new CustomEvent("unlock-request", {
        detail: {
          nodeId: this.selectedNodeId,
          cost: cost,
        },
        bubbles: true,
        composed: true,
      })
    );
  }

  /**
   * Gets node icon based on type
   * @param {Object} nodeDef - Node definition
   * @returns {string}
   */
  _getNodeIcon(nodeDef) {
    if (!nodeDef || !nodeDef.type) return "❓";

    switch (nodeDef.type) {
      case "STAT_BOOST":
        return "📈";
      case "ACTIVE_SKILL":
        return "⚔️";
      case "PASSIVE_ABILITY":
        return "✨";
      default:
        return "🔷";
    }
  }

  /**
   * Gets node name/title
   * @param {Object} nodeDef - Node definition
   * @returns {string}
   */
  _getNodeName(nodeDef) {
    if (nodeDef.data?.name) {
      return nodeDef.data.name;
    }
    if (nodeDef.type === "STAT_BOOST" && nodeDef.data?.stat) {
      return `${nodeDef.data.stat} +${nodeDef.data.value || 0}`;
    }
    return nodeDef.type || "Unknown";
  }

  /**
   * Gets unlock validation error message
   * @param {string} nodeId - Node ID
   * @returns {string|null}
   */
  _getUnlockError(nodeId) {
    if (!this.unit || !this.selectedNodeId) return null;

    const tree = this._getTreeDefinition();
    if (!tree) return "Tree definition not found";

    const nodeDef = tree.nodes[nodeId];
    if (!nodeDef) return "Node not found";

    const status = this._calculateNodeStatus(nodeId, nodeDef);
    const mastery = this.unit.classMastery[this.unit.activeClassId];

    if (status === "LOCKED") {
      const levelReq = nodeDef.req || 1;
      const unitLevel = mastery?.level || 1;
      const parentNodes = this._findParentNodes(nodeId);

      if (parentNodes.length > 0) {
        const unlockedParents = parentNodes.filter((pid) =>
          mastery.unlockedNodes?.includes(pid)
        );
        if (unlockedParents.length === 0) {
          const firstParent = tree.nodes[parentNodes[0]];
          return `Requires: ${this._getNodeName(firstParent)}`;
        }
      }

      if (unitLevel < levelReq) {
        return `Requires Level ${levelReq}`;
      }

      return "Node is locked";
    }

    if (status === "AVAILABLE") {
      const cost = nodeDef.cost || 1;
      const skillPoints = mastery?.skillPoints || 0;

      if (skillPoints < cost) {
        return "Insufficient Points";
      }
    }

    return null;
  }

  /**
   * Groups nodes by tier
   * @returns {Object}
   */
  _groupNodesByTier() {
    const tree = this._getTreeDefinition();
    if (!tree) return {};

    const tiers = {};
    for (const [nodeId, nodeDef] of Object.entries(tree.nodes)) {
      const tier = nodeDef.tier || 1;
      if (!tiers[tier]) {
        tiers[tier] = [];
      }
      tiers[tier].push({ id: nodeId, def: nodeDef });
    }

    return tiers;
  }

  render() {
    if (!this.unit) {
      return html`<div class="placeholder">No unit selected</div>`;
    }

    const tree = this._getTreeDefinition();
    if (!tree) {
      return html`<div class="placeholder">No skill tree available</div>`;
    }

    const tiers = this._groupNodesByTier();
    const sortedTiers = Object.keys(tiers)
      .map(Number)
      .sort((a, b) => b - a); // Reverse order for column-reverse

    const selectedNodeDef =
      this.selectedNodeId && tree.nodes[this.selectedNodeId]
        ? tree.nodes[this.selectedNodeId]
        : null;
    const selectedStatus = selectedNodeDef
      ? this._calculateNodeStatus(this.selectedNodeId, selectedNodeDef)
      : null;
    const unlockError = selectedNodeDef
      ? this._getUnlockError(this.selectedNodeId)
      : null;
    const mastery = this.unit.classMastery?.[this.unit.activeClassId];
    const skillPoints = mastery?.skillPoints || 0;
    const canUnlock =
      selectedStatus === "AVAILABLE" &&
      !unlockError &&
      skillPoints >= (selectedNodeDef?.cost || 1);

    return html`
      <div class="tree-container">
        <div class="connections-overlay">
          <svg width="100%" height="100%">
            <!-- Connection lines will be drawn here -->
          </svg>
        </div>

        <div class="tree-content">
          ${sortedTiers.map(
            (tier) => html`
              <div class="tier-row">
                <div class="tier-label">Tier ${tier}</div>
                ${tiers[tier].map(({ id, def }) => {
                  const status = this._calculateNodeStatus(id, def);
                  return html`
                    <div
                      class="voxel-node ${status.toLowerCase()}"
                      data-node-id="${id}"
                      @click="${() => this._handleNodeClick(id)}"
                      title="${this._getNodeName(def)}"
                    >
                      <div class="voxel-cube">
                        <div class="cube-face front">
                          <div class="node-icon">${this._getNodeIcon(def)}</div>
                        </div>
                        <div class="cube-face back"></div>
                        <div class="cube-face right"></div>
                        <div class="cube-face left"></div>
                        <div class="cube-face top"></div>
                        <div class="cube-face bottom"></div>
                      </div>
                    </div>
                  `;
                })}
              </div>
            `
          )}
        </div>
      </div>

      <!-- Inspector Footer -->
      <div class="inspector ${this.selectedNodeId ? "visible" : ""}">
        <div class="inspector-content">
          ${selectedNodeDef
            ? html`
                <div class="inspector-header">
                  <h3 class="inspector-title">
                    ${this._getNodeName(selectedNodeDef)}
                  </h3>
                  <button
                    class="inspector-close"
                    @click="${() => {
                      this.selectedNodeId = null;
                      this.requestUpdate();
                    }}"
                    aria-label="Close inspector"
                  >
                    ×
                  </button>
                </div>
                <p class="inspector-description">
                  ${selectedNodeDef.data?.description ||
                  `Type: ${selectedNodeDef.type}`}
                </p>
                ${selectedNodeDef.req
                  ? html`<div class="inspector-requirements">
                      Level Requirement: ${selectedNodeDef.req}<br />
                      Cost: ${selectedNodeDef.cost || 1} Skill Point(s)
                    </div>`
                  : ""}
                <button
                  class="unlock-button"
                  @click="${this._handleUnlock}"
                  ?disabled="${!canUnlock}"
                >
                  ${selectedStatus === "UNLOCKED"
                    ? "Unlocked"
                    : selectedStatus === "AVAILABLE"
                    ? `Unlock (${selectedNodeDef.cost || 1} SP)`
                    : "Locked"}
                </button>
                ${unlockError
                  ? html`<div class="error-message">${unlockError}</div>`
                  : ""}
              `
            : html`<p>Select a node to view details</p>`}
        </div>
      </div>
    `;
  }
}

customElements.define("skill-tree-ui", SkillTreeUI);
