<script setup lang="ts">
import { ref, computed, onMounted } from "vue";
import dayjs from "dayjs";
import RankBadge from "@/components/RankBadge.vue";
import {
  createColumnHelper,
  useVueTable,
  getCoreRowModel,
  getFilteredRowModel,
  getSortedRowModel,
  type ColumnFiltersState,
  type SortingState,
} from "@tanstack/vue-table";

interface Objective {
  objectiv_id: string;
  display_string: string;
  first_seen_at: string | null;
  count: number;
  max_count: number;
  seed: string | null;
  points_per_objectiv: number;
  total_points: number;
}

const userInfo = ref({
  username: "Player",
  rank: null as number | null,
  score: 0,
  runsSubmitted: 0,
  deathsCount: 0,
  isStaff: false,
});

const uploadedFiles = ref<File[]>([]);
const isUploading = ref(false);
const isDragover = ref(false);
const objectives = ref<Objective[]>([]);
const isLoadingLeaderboard = ref(false);
const leaderboard = ref<any[]>([]);

const columnHelper = createColumnHelper<Objective>();
const sorting = ref<SortingState>([]);
const columnFilters = ref<ColumnFiltersState>([]);

const formatDate = (dateString: string | null) => {
  if (!dateString) {
    return ""
  }
  const date = dayjs(dateString);
  return date.format("MMM DD, YYYY HH:mm");
};

const columns = [
  columnHelper.accessor("objectiv_id", {
    header: "Objective ID",
    cell: (info) => info.getValue(),
  }),
  columnHelper.accessor("total_points", {
    header: "Your points",
    cell: (info) => info.getValue() || 0,
  }),
  columnHelper.accessor("first_seen_at", {
    header: "First seen",
    cell: (info) => formatDate(info.getValue()),
    sortingFn: (rowA, rowB) => {
      const dateA = dayjs(rowA.original.first_seen_at);
      const dateB = dayjs(rowB.original.first_seen_at);
      if (!rowA.original.first_seen_at) {
        return rowB.original.first_seen_at ? 1 : 0
      }
      if (!rowB.original.first_seen_at) {
        return rowA.original.first_seen_at ? 0 : 1
      }
      return dateA.isBefore(dateB) ? -1 : dateA.isAfter(dateB) ? 1 : 0;
    },
  }),
  columnHelper.accessor("seed", {
    header: "Seed",
    cell: (info) => info.getValue(),
  }),
];

const table = computed(() =>
  useVueTable({
    get data() {
      return objectives.value;
    },
    columns,
    state: {
      get sorting() {
        return sorting.value;
      },
      get columnFilters() {
        return columnFilters.value;
      },
    },
    onSortingChange: (updater) => {
      sorting.value =
        typeof updater === "function" ? updater(sorting.value) : updater;
    },
    onColumnFiltersChange: (updater) => {
      columnFilters.value =
        typeof updater === "function" ? updater(columnFilters.value) : updater;
    },
    getCoreRowModel: getCoreRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    getSortedRowModel: getSortedRowModel(),
    filterFns: {
      fuzzy: (row, columnId, value) => {
        const itemData = row.getValue(columnId);
        const searchValue = value.toLowerCase();
        if (columnId === "first_seen_at") {
          return formatDate(itemData as string).includes(searchValue)
        }
        return String(itemData).toLowerCase().includes(searchValue);
      },
    },
  })
);

const filteredObjectives = computed(() => table.value.getRowModel().rows);

const handleFileUpload = (event: Event) => {
  const input = event.target as HTMLInputElement;
  if (input.files) {
    uploadedFiles.value = Array.from(input.files);
  }
};

const handleDragover = (event: DragEvent) => {
  event.preventDefault();
  event.stopPropagation();
  isDragover.value = true;
};

const handleDragleave = (event: DragEvent) => {
  event.preventDefault();
  event.stopPropagation();
  isDragover.value = false;
};

const handleDrop = (event: DragEvent) => {
  event.preventDefault();
  event.stopPropagation();
  isDragover.value = false;

  if (event.dataTransfer?.files) {
    uploadedFiles.value = Array.from(event.dataTransfer.files);
  }
};

const submitRun = async () => {
  if (uploadedFiles.value.length === 0) return;

  isUploading.value = true;
  try {
    for (const file of uploadedFiles.value) {
      const formData = new FormData();
      formData.append("file", file);

      const response = await fetch("/api/noita/submit", {
        method: "POST",
        body: formData,
      });

      if (!response.ok) {
        const error = await response.json();
        alert(`Error submitting ${file.name}: ${error.detail || "Unknown error"}`);
        return;
      }

      const result = await response.json();
      console.log("Submission successful:", result);
    }

    uploadedFiles.value = [];
    alert("Run submitted successfully!");

    // Refresh objectives, score, and rank after successful submission
    await Promise.all([
      fetchUserResults(),
      fetchLeaderboard(),
    ]);
  } catch (error) {
    console.error("Error submitting run:", error);
    alert("Error submitting run. Please try again.");
  } finally {
    isUploading.value = false;
  }
};

const goHome = () => {
  window.location.href = "/";
};

const fetchUserResults = async () => {
  try {
    const response = await fetch("/api/noita/results");
    if (!response.ok) throw new Error("Failed to fetch results");

    const results = await response.json();
    userInfo.value.score = results.total_score;
    userInfo.value.deathsCount = results.deaths_count;
    userInfo.value.runsSubmitted = results.objectives.length;
    objectives.value = results.objectives;
  } catch (error) {
    console.error("Error fetching results:", error);
  }
};

const fetchLeaderboard = async () => {
  isLoadingLeaderboard.value = true;
  try {
    const response = await fetch("/api/noita/leaderboard");
    if (!response.ok) throw new Error("Failed to fetch leaderboard");

    const data = await response.json();
    leaderboard.value = data.leaderboard;

    // Find current user's rank
    const userRank = leaderboard.value.find(
      (entry: any) => entry.username === userInfo.value.username
    );

    if (userRank) {
      userInfo.value.rank = userRank.rank;
      userInfo.value.score = userRank.total_score;
      userInfo.value.deathsCount = userRank.deaths_count;
    }
  } catch (error) {
    console.error("Error fetching leaderboard:", error);
  } finally {
    isLoadingLeaderboard.value = false;
  }
};

const clearCache = async () => {
  try {
    const response = await fetch("/api/cache/clear", {
      method: "POST",
    });

    if (response.ok) {
      alert("Cache cleared successfully!");
      // Refresh data after clearing cache
      await Promise.all([
        fetchUserResults(),
        fetchLeaderboard(),
      ]);
    } else {
      const error = await response.json();
      alert(`Error clearing cache: ${error.detail || "Unknown error"}`);
    }
  } catch (error) {
    console.error("Error clearing cache:", error);
    alert("Error clearing cache. Please try again.");
  }
};

const loadUserData = async () => {
  // Get user info first
  try {
    const response = await fetch("/api/user");
    if (response.ok) {
      const user = await response.json();
      if (user.is_authenticated) {
        userInfo.value.username = user.username;
        userInfo.value.isStaff = user.is_staff || false;
      }
    }
  } catch (error) {
    console.error("Error fetching user info:", error);
  }

  // Fetch results and leaderboard
  await Promise.all([
    fetchUserResults(),
    fetchLeaderboard(),
  ]);
};

onMounted(() => {
  loadUserData();
});
</script>

<template>
  <div class="min-h-screen bg-base-200">
    <!-- Header -->
    <div class="navbar bg-base-100 shadow-lg">
      <div class="container min-w-3/4 mx-auto w-full flex items-center gap-4">
        <button @click="goHome" class="btn btn-primary btn-sm">
          <i class="mdi mdi-arrow-left"></i>
          Back
        </button>
        <h1 class="text-xl font-bold">Noita Submitter</h1>
        <div class="flex-1"></div>
        <a href="/api/docs" class="btn btn-xs">API docs</a>
        <a href="/admin" class="btn btn-xs btn-warning">Admin panel</a>
      </div>
    </div>

    <!-- Main Content -->
    <div class="container min-w-3/4 mx-auto px-4 py-8">
      <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
        <!-- Left Column: User Ranking -->
        <div class="lg:col-span-1">
          <div class="card bg-base-100 shadow-lg sticky top-8">
            <div class="bg-gradient-to-br from-purple-600 to-purple-400 p-8 text-white rounded-t-2xl">
              <h2 class="text-3xl font-bold">
                <i class="mdi mdi-trophy text-3xl"></i>
                Your Ranking
              </h2>
            </div>
            <div class="card-body p-8">
              <div class="text-center mb-8">
                <p class="text-base text-base-content/70">Player</p>
                <p class="text-4xl font-bold mt-2">{{ userInfo.username }}</p>
              </div>

              <div class="divider"></div>

              <div v-if="isLoadingLeaderboard" class="flex justify-center py-8">
                <span class="loading loading-spinner loading-lg"></span>
              </div>

              <div v-else class="space-y-6">
                <div class="text-center">
                  <p class="text-base text-base-content/70 mb-3">Current Rank</p>
                  <RankBadge :rank="userInfo.rank" />
                </div>

                <div class="text-center">
                  <p class="text-base text-base-content/70 mb-2">Total Score</p>
                  <p class="text-3xl font-bold">{{ userInfo.score.toLocaleString() }}</p>
                </div>

                <div class="text-center">
                  <p class="text-base text-base-content/70 mb-2">Objectives Completed</p>
                  <p class="text-3xl font-bold">{{ userInfo.runsSubmitted }}</p>
                </div>

                <div class="text-center">
                  <p class="text-base text-base-content/70 mb-2">Deaths</p>
                  <p class="text-3xl font-bold text-error">{{ userInfo.deathsCount }}</p>
                </div>
              </div>

              <!-- Leaderboard Table -->
              <div class="mt-6">
                <h3 class="font-bold text-lg mb-3">Global Leaderboard</h3>
                <div class="overflow-x-auto">
                  <table class="table table-sm w-full">
                    <thead>
                      <tr>
                        <th>Rank</th>
                        <th>Player</th>
                        <th class="text-right">Score</th>
                        <th class="text-right">Objectives</th>
                        <th class="text-right">Deaths</th>
                      </tr>
                    </thead>
                    <tbody>
                      <tr v-for="entry in leaderboard" :key="entry.username"
                        :class="{ 'bg-primary/20': entry.username === userInfo.username }">
                        <td class="font-bold">
                          <RankBadge :rank="entry.rank" />
                        </td>
                        <td class="text-sm">
                          {{ entry.username }}
                          <span v-if="entry.username === userInfo.username" class="badge badge-primary badge-sm ml-1">
                            You
                          </span>
                          <span v-if="entry.is_staff" class="badge badge-warning badge-sm ml-1">
                            admin
                          </span>
                        </td>
                        <td class="text-right text-sm font-bold text-primary">{{ entry.total_score.toLocaleString() }}
                        </td>
                        <td class="text-right text-sm">{{ entry.objectives_count }}</td>
                        <td class="text-right text-sm text-error">{{ entry.deaths_count }}</td>
                      </tr>
                    </tbody>
                  </table>
                </div>
              </div>

              <button v-if="userInfo.isStaff" @click="clearCache" class="btn btn-error btn-sm w-full mt-3">
                <i class="mdi mdi-cache-clear mr-1"></i>
                Clear Cache
              </button>
            </div>
          </div>
        </div>

        <!-- Right Column: Upload -->
        <div class="lg:col-span-1">
          <div class="card bg-base-100 shadow-lg">
            <div class="card-body">
              <h2 class="card-title text-2xl mb-6">
                <i class="mdi mdi-cloud-upload text-purple-500 mr-2"></i>
                Submit Your Run
              </h2>

              <!-- Upload Area -->
              <div @dragover="handleDragover" @dragleave="handleDragleave" @drop="handleDrop" :class="[
                'border-2 border-dashed rounded-lg p-8 text-center transition-colors cursor-pointer bg-base-200/50 mb-6',
                isDragover ? 'border-primary bg-primary/10' : 'border-base-300 hover:border-primary'
              ]">
                <input type="file" multiple @change="handleFileUpload" class="hidden" id="file-upload"
                  accept="text/plain,text/x-log" />
                <label for="file-upload" class="cursor-pointer flex flex-col items-center gap-3">
                  <i
                    :class="['mdi text-4xl', isDragover ? 'mdi-cloud-check text-primary' : 'mdi-file-upload text-base-content/50']"></i>
                  <div>
                    <p class="font-semibold">Click to upload or drag and drop</p>
                    <p class="text-sm text-base-content/70">The log file <code>polylan_mod_log.txt</code></p>
                  </div>
                </label>
              </div>

              <!-- Uploaded Files List -->
              <div v-if="uploadedFiles.length > 0" class="mb-6">
                <p class="font-semibold mb-3">Selected Files:</p>
                <div class="space-y-2">
                  <div v-for="(file, index) in uploadedFiles" :key="index"
                    class="flex items-center gap-3 bg-base-200 p-3 rounded-lg">
                    <i class="mdi mdi-file text-primary"></i>
                    <div class="flex-1 min-w-0">
                      <p class="font-medium truncate">{{ file.name }}</p>
                      <p class="text-xs text-base-content/70">{{ (file.size / 1024 / 1024).toFixed(2) }} MB</p>
                    </div>
                    <button @click="uploadedFiles.splice(index, 1)" class="btn btn-ghost btn-xs">
                      <i class="mdi mdi-close"></i>
                    </button>
                  </div>
                </div>
              </div>

              <!-- Submit Button -->
              <div class="flex gap-3">
                <label for="file-upload" class="btn btn-outline flex-1">
                  <i class="mdi mdi-folder-open mr-2"></i>
                  Choose Files
                </label>
                <button @click="submitRun" :disabled="uploadedFiles.length === 0 || isUploading"
                  :class="['btn btn-primary flex-1', { 'loading': isUploading }]">
                  <i v-if="!isUploading" class="mdi mdi-send mr-2"></i>
                  {{ isUploading ? 'Submitting...' : 'Submit Run' }}
                </button>
              </div>

              <p class="text-xs text-base-content/70 text-center mt-4">
                Maximum file size: 256 MB per file
              </p>
            </div>
          </div>

          <!-- Objectives Table -->
          <div class="card bg-base-100 shadow-lg mt-8">
            <div class="card-body">
              <h2 class="card-title text-2xl mb-6">
                <i class="mdi mdi-view-list text-purple-500 mr-2"></i>
                Objectives
              </h2>

              <div v-if="objectives.length === 0" class="text-center py-8">
                <p class="text-base-content/70 mb-2">No objectives completed yet</p>
                <p class="text-sm text-base-content/50">Submit your runs to unlock objectives!</p>
              </div>

              <div v-if="objectives.length > 0" class="space-y-4">
                <!-- Search Input -->
                <input :value="columnFilters.find((f) => f.id === 'objectiv_id')?.value ?? ''" @input="
                  (e) => {
                    const target = e.target as HTMLInputElement;
                    table.getColumn('objectiv_id')?.setFilterValue(target.value);
                  }
                " type="text" placeholder="Search objectives..." class="input input-bordered w-full" />

                <!-- Results Summary -->
                <div class="text-sm text-base-content/70">
                  Showing {{ filteredObjectives.length }} of {{ objectives.length }} objectives
                </div>

                <!-- Objectives Table -->
                <div v-if="filteredObjectives.length > 0" class="overflow-x-auto">
                  <table class="table table-zebra w-full">
                    <thead>
                      <tr>
                        <th v-for="header in table.getHeaderGroups()[0]?.headers" :key="header.id" :class="[
                          'cursor-pointer hover:bg-base-300',
                          header.column.columnDef.id === 'objectiv_id' ? 'text-left' : 'text-right',
                        ]" @click="header.column.toggleSorting()">
                          <div class="flex items-center justify-between">
                            <span v-if="header.column.columnDef.id === 'objectiv_id'">
                              {{ header.isPlaceholder ? null : header.column.columnDef.header }}
                            </span>
                            <span v-else class="ml-auto">
                              {{ header.isPlaceholder ? null : header.column.columnDef.header }}
                            </span>
                            <i v-if="header.column.getIsSorted()" :class="[
                              'mdi ml-2',
                              header.column.getIsSorted() === 'desc'
                                ? 'mdi-arrow-down'
                                : 'mdi-arrow-up',
                            ]"></i>
                          </div>
                        </th>
                      </tr>
                    </thead>
                    <tbody>
                      <tr v-for="row in filteredObjectives" :key="row.id">
                        <td v-for="cell in row.getVisibleCells()" :key="cell.id" :class="[
                          cell.column.id === 'objectiv_id'
                            ? 'font-medium'
                            : 'text-right',
                        ]">
                          <template v-if="cell.column.id === 'objectiv_id'">
                            <a :href="`https://noita.wiki.gg/wiki/${row.original.objectiv_id}`" target="_blank">
                              {{ row.original.display_string }}
                              <i class="mdi mdi-open-in-new"></i>
                            </a>
                          </template>
                          <template v-else-if="cell.column.id === 'total_points'">
                            <span :class="row.original.count >= row.original.max_count ? 'text-primary' : 'text-error'">
                              {{ row.original.total_points }} / {{ row.original.points_per_objectiv *
                                row.original.max_count }}
                            </span>
                          </template>
                          <template v-else-if="cell.column.id === 'first_seen_at'">
                            <span :title="formatDate(row.original.first_seen_at)">
                              {{ formatDate(row.original.first_seen_at) }}
                            </span>
                          </template>
                          <template v-else>
                            {{ cell.renderValue() }}
                          </template>
                        </td>
                      </tr>
                    </tbody>
                  </table>
                </div>

                <!-- No Results -->
                <div v-if="filteredObjectives.length === 0" class="text-center py-8">
                  <p class="text-base-content/70">No objectives match your search</p>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

  </div>
</template>
