<template>
  <div>
    <v-tabs v-model="activeTab" color="primary">
      <v-tab value="profile">Profile</v-tab>
      <v-tab value="connections">Bank Connections</v-tab>
      <v-tab value="history">Sync History</v-tab>
      <v-tab value="ai">AI</v-tab>
    </v-tabs>

    <v-tabs-window v-model="activeTab" class="mt-4">
      <!-- Tab 1: Profile -->
      <v-tabs-window-item value="profile">
        <!-- Profile Info Card -->
        <v-card class="mb-6">
          <v-card-title>Profile Information</v-card-title>
          <v-card-text>
            <v-text-field
              v-model="profileForm.displayName"
              label="Display Name"
              variant="outlined"
              class="mb-4"
              placeholder="Enter a display name..."
            />
            <v-text-field
              v-model="profileForm.email"
              label="Email"
              variant="outlined"
              class="mb-4"
              type="email"
            />
            <v-text-field
              :model-value="authStore.username"
              label="Username"
              readonly
              variant="outlined"
              class="mb-4"
              hint="Username cannot be changed"
              persistent-hint
            />
            <v-btn color="primary" :loading="profileSaving" @click="saveProfile">Save</v-btn>
          </v-card-text>
        </v-card>

        <!-- Change Password Card -->
        <v-card class="mb-6">
          <v-card-title>Change Password</v-card-title>
          <v-card-text>
            <v-text-field
              v-model="passwordForm.currentPassword"
              label="Current Password"
              variant="outlined"
              type="password"
              class="mb-4"
            />
            <v-text-field
              v-model="passwordForm.newPassword"
              label="New Password"
              variant="outlined"
              type="password"
              class="mb-4"
            />
            <v-text-field
              v-model="passwordForm.confirmPassword"
              label="Confirm New Password"
              variant="outlined"
              type="password"
              class="mb-4"
              :error-messages="passwordForm.confirmPassword && passwordForm.newPassword !== passwordForm.confirmPassword ? ['Passwords do not match'] : []"
            />
            <v-btn
              color="primary"
              :loading="passwordChanging"
              :disabled="!passwordForm.currentPassword || !passwordForm.newPassword || passwordForm.newPassword !== passwordForm.confirmPassword"
              @click="changePassword"
            >
              Change Password
            </v-btn>
          </v-card-text>
        </v-card>

        <!-- Account Info Card -->
        <v-card class="mb-6">
          <v-card-title>Account Info</v-card-title>
          <v-card-text>
            <div class="text-body-1 mb-2">
              <strong>Member since:</strong> {{ profile ? new Date(profile.createdAt).toLocaleDateString(undefined, { year: 'numeric', month: 'long', day: 'numeric' }) : '-' }}
            </div>
            <div class="text-body-1">
              <strong>Last login:</strong> {{ profile?.lastLoginAt ? new Date(profile.lastLoginAt).toLocaleString() : 'Never' }}
            </div>
          </v-card-text>
        </v-card>

        <!-- Danger Zone Card -->
        <v-card variant="outlined" color="error">
          <v-card-title class="text-error">Danger Zone</v-card-title>
          <v-card-text>
            <p class="text-body-2 mb-4">Permanently delete your account and all associated data. This action cannot be undone.</p>
            <v-btn color="error" variant="tonal" @click="showDeleteAccountDialog = true">Delete Account</v-btn>
          </v-card-text>
        </v-card>

        <!-- Delete Account Confirmation Dialog -->
        <v-dialog v-model="showDeleteAccountDialog" max-width="400">
          <v-card>
            <v-card-title class="text-error">Delete Account</v-card-title>
            <v-card-text>
              Are you sure you want to permanently delete your account? All your data including accounts, transactions, and settings will be removed. This cannot be undone.
            </v-card-text>
            <v-card-actions>
              <v-spacer />
              <v-btn @click="showDeleteAccountDialog = false">Cancel</v-btn>
              <v-btn color="error" :loading="accountDeleting" @click="deleteAccount">Delete</v-btn>
            </v-card-actions>
          </v-card>
        </v-dialog>

        <!-- Profile Snackbars -->
        <v-snackbar v-model="showProfileSuccess" :timeout="4000" color="success">
          {{ profileSuccessMessage }}
        </v-snackbar>
        <v-snackbar v-model="showProfileError" :timeout="6000" color="error">
          {{ profileErrorMessage }}
        </v-snackbar>
      </v-tabs-window-item>

      <!-- Tab 2: Bank Connections -->
      <v-tabs-window-item value="connections">

        <v-tabs v-model="activeProviderTab" color="primary" class="mb-4">
          <v-tab value="simplefin">
            <v-icon start size="small">mdi-link-variant</v-icon>
            SimpleFIN
            <v-chip v-if="simpleFinConnections.length" color="green" size="x-small" class="ml-2">{{ simpleFinConnections.length }}</v-chip>
          </v-tab>
          <v-tab value="plaid">
            <v-icon start size="small">mdi-bank</v-icon>
            Plaid
            <v-chip v-if="plaidConnections.length" color="blue" size="x-small" class="ml-2">{{ plaidConnections.length }}</v-chip>
          </v-tab>
        </v-tabs>

        <v-tabs-window v-model="activeProviderTab">
          <!-- SimpleFIN sub-tab -->
          <v-tabs-window-item value="simplefin">
            <div class="d-flex align-center flex-wrap ga-2 mb-4">
              <v-btn size="small" variant="tonal" color="secondary" prepend-icon="mdi-link-plus" @click="showSimpleFinDialog = true">
                Connect
              </v-btn>
              <v-btn
                size="small"
                variant="tonal"
                color="primary"
                prepend-icon="mdi-sync"
                :loading="syncingAllSimpleFin"
                :disabled="simpleFinConnections.filter(c => c.isActive).length === 0"
                @click="syncAllSimpleFin"
              >
                Sync All
              </v-btn>
              <v-btn
                size="small"
                variant="tonal"
                color="secondary"
                prepend-icon="mdi-refresh"
                :loading="resyncingAllSimpleFin"
                :disabled="simpleFinConnections.filter(c => c.isActive).length === 0"
                @click="resyncAllSimpleFin"
              >
                Re-sync All
              </v-btn>
              <v-spacer />
              <v-select
                v-model="simpleFinGlobalInterval"
                :items="intervalOptions"
                item-title="text"
                item-value="value"
                label="Sync Interval"
                density="compact"
                variant="outlined"
                hide-details
                style="max-width: 220px"
                @update:model-value="updateSimpleFinGlobalInterval"
              />
            </div>

            <v-alert v-if="simpleFinConnections.length === 0 && !loading" type="info" variant="tonal" class="mb-4">
              No SimpleFIN connections yet. Click Connect to add one.
            </v-alert>

            <v-expansion-panels v-model="expandedSimpleFinPanels" multiple>
              <v-expansion-panel v-for="conn in simpleFinConnections" :key="conn.id" :value="conn.id">
                <v-expansion-panel-title>
                  <div class="d-flex align-center flex-grow-1 mr-2">
                    <span class="text-subtitle-2">{{ conn.institutionName }}</span>
                    <v-chip :color="conn.isActive ? 'success' : 'grey'" size="x-small" class="ml-2">
                      {{ conn.isActive ? 'Active' : 'Inactive' }}
                    </v-chip>
                    <v-chip size="x-small" variant="tonal" class="ml-1">
                      {{ conn.linkedAccounts.length }} account{{ conn.linkedAccounts.length !== 1 ? 's' : '' }}
                    </v-chip>
                    <v-chip v-if="syncingConnections[conn.id]" size="x-small" color="info" class="ml-1">
                      Syncing...
                    </v-chip>
                  </div>
                </v-expansion-panel-title>
                <v-expansion-panel-text>
                  <div class="d-flex align-center flex-wrap ga-2 mb-3">
                    <v-btn variant="text" :color="conn.isActive ? 'warning' : 'success'" size="small" @click="toggleConnection(conn)">
                      {{ conn.isActive ? 'Disable' : 'Enable' }}
                    </v-btn>
                    <v-btn variant="text" color="error" size="small" prepend-icon="mdi-delete" @click="confirmDeleteConnection(conn)">
                      Delete
                    </v-btn>
                    <v-spacer />
                    <span class="text-body-2 text-medium-emphasis">
                      Last synced: {{ conn.lastSyncAt ? new Date(conn.lastSyncAt).toLocaleString() : 'Never' }}
                    </span>
                  </div>
                  <v-alert v-if="conn.lastSyncError" type="error" variant="tonal" density="compact" class="mb-3">
                    {{ conn.lastSyncError }}
                  </v-alert>

                  <v-table density="compact" v-if="conn.linkedAccounts.length > 0">
                    <thead>
                      <tr>
                        <th>External Account</th>
                        <th>Type</th>
                        <th>Balance</th>
                        <th>Purrse Account</th>
                        <th>Enabled</th>
                        <th>Last Synced</th>
                      </tr>
                    </thead>
                    <tbody>
                      <tr v-for="la in conn.linkedAccounts" :key="la.id">
                        <td>{{ la.externalAccountName }}</td>
                        <td>{{ la.externalAccountType }}</td>
                        <td>{{ la.lastKnownBalance != null ? formatCurrency(la.lastKnownBalance) : '-' }}</td>
                        <td>
                          <v-select
                            :model-value="la.accountId"
                            :items="accountOptions"
                            item-title="text"
                            item-value="value"
                            density="compact"
                            variant="outlined"
                            hide-details
                            clearable
                            placeholder="Select account..."
                            @update:model-value="(val: string | null) => updateLinkedAccount(la, val)"
                          />
                        </td>
                        <td>
                          <v-switch
                            :model-value="la.isEnabled"
                            density="compact"
                            hide-details
                            color="primary"
                            @update:model-value="(val: boolean | null) => toggleLinkedAccount(la, val ?? false)"
                          />
                        </td>
                        <td class="text-body-2">{{ la.lastSyncAt ? new Date(la.lastSyncAt).toLocaleString() : 'Never' }}</td>
                      </tr>
                    </tbody>
                  </v-table>
                </v-expansion-panel-text>
              </v-expansion-panel>
            </v-expansion-panels>
          </v-tabs-window-item>

          <!-- Plaid sub-tab -->
          <v-tabs-window-item value="plaid">
            <!-- Plaid API Credentials -->
            <v-card variant="outlined" class="mb-4">
              <v-card-text>
                <div class="d-flex align-center mb-2">
                  <v-icon size="small" class="mr-1">mdi-key</v-icon>
                  <span class="text-subtitle-2">API Credentials</span>
                  <v-chip v-if="plaidCredentials.isConfigured" color="success" size="x-small" class="ml-2">Configured</v-chip>
                  <v-chip v-else color="warning" size="x-small" class="ml-2">Not configured</v-chip>
                </div>
                <p class="text-body-2 text-medium-emphasis mb-3">
                  Enter your Plaid developer credentials. Get them from your Plaid dashboard.
                </p>
                <v-row dense>
                  <v-col cols="12" sm="4">
                    <v-text-field
                      v-model="plaidForm.clientId"
                      label="Client ID"
                      variant="outlined"
                      density="compact"
                      :placeholder="plaidCredentials.isConfigured ? '(saved)' : ''"
                    />
                  </v-col>
                  <v-col cols="12" sm="4">
                    <v-text-field
                      v-model="plaidForm.secret"
                      label="Secret"
                      variant="outlined"
                      density="compact"
                      type="password"
                      :placeholder="plaidCredentials.isConfigured ? '(saved)' : ''"
                    />
                  </v-col>
                  <v-col cols="12" sm="2">
                    <v-select
                      v-model="plaidForm.environment"
                      :items="plaidEnvironments"
                      label="Environment"
                      variant="outlined"
                      density="compact"
                    />
                  </v-col>
                  <v-col cols="12" sm="2" class="d-flex align-center">
                    <v-btn
                      color="primary"
                      :loading="plaidCredsSaving"
                      :disabled="!plaidForm.clientId || !plaidForm.secret"
                      @click="savePlaidCredentials"
                    >
                      Save
                    </v-btn>
                  </v-col>
                </v-row>
              </v-card-text>
            </v-card>

            <div class="d-flex align-center flex-wrap ga-2 mb-4">
              <v-btn
                size="small"
                variant="tonal"
                color="primary"
                prepend-icon="mdi-bank-plus"
                :loading="plaidLoading"
                :disabled="!plaidCredentials.isConfigured"
                @click="startPlaidLink"
              >
                Connect
              </v-btn>
              <v-btn
                size="small"
                variant="tonal"
                color="primary"
                prepend-icon="mdi-sync"
                :loading="syncingAllPlaid"
                :disabled="plaidConnections.filter(c => c.isActive).length === 0"
                @click="syncAllPlaid"
              >
                Sync All
              </v-btn>
            </div>

            <v-alert v-if="plaidConnections.length === 0 && !loading" type="info" variant="tonal" class="mb-4">
              No Plaid connections yet. Configure your API credentials above, then click Connect.
            </v-alert>

            <v-expansion-panels v-model="expandedPlaidPanels" multiple>
              <v-expansion-panel v-for="conn in plaidConnections" :key="conn.id" :value="conn.id">
                <v-expansion-panel-title>
                  <div class="d-flex align-center flex-grow-1 mr-2">
                    <span class="text-subtitle-2">{{ conn.institutionName }}</span>
                    <v-chip :color="conn.isActive ? 'success' : 'grey'" size="x-small" class="ml-2">
                      {{ conn.isActive ? 'Active' : 'Inactive' }}
                    </v-chip>
                    <v-chip size="x-small" variant="tonal" class="ml-1">
                      {{ conn.linkedAccounts.length }} account{{ conn.linkedAccounts.length !== 1 ? 's' : '' }}
                    </v-chip>
                    <v-chip v-if="syncingConnections[conn.id]" size="x-small" color="info" class="ml-1">
                      Syncing...
                    </v-chip>
                  </div>
                </v-expansion-panel-title>
                <v-expansion-panel-text>
                  <div class="d-flex align-center flex-wrap ga-2 mb-3">
                    <v-btn variant="text" :color="conn.isActive ? 'warning' : 'success'" size="small" @click="toggleConnection(conn)">
                      {{ conn.isActive ? 'Disable' : 'Enable' }}
                    </v-btn>
                    <v-btn variant="text" color="error" size="small" prepend-icon="mdi-delete" @click="confirmDeleteConnection(conn)">
                      Delete
                    </v-btn>
                    <v-spacer />
                    <span class="text-body-2 text-medium-emphasis">
                      Last synced: {{ conn.lastSyncAt ? new Date(conn.lastSyncAt).toLocaleString() : 'Never' }}
                    </span>
                  </div>
                  <v-alert v-if="conn.lastSyncError" type="error" variant="tonal" density="compact" class="mb-3">
                    {{ conn.lastSyncError }}
                  </v-alert>

                  <v-table density="compact" v-if="conn.linkedAccounts.length > 0">
                    <thead>
                      <tr>
                        <th>External Account</th>
                        <th>Type</th>
                        <th>Balance</th>
                        <th>Purrse Account</th>
                        <th>Enabled</th>
                        <th>Last Synced</th>
                      </tr>
                    </thead>
                    <tbody>
                      <tr v-for="la in conn.linkedAccounts" :key="la.id">
                        <td>{{ la.externalAccountName }}</td>
                        <td>{{ la.externalAccountType }}</td>
                        <td>{{ la.lastKnownBalance != null ? formatCurrency(la.lastKnownBalance) : '-' }}</td>
                        <td>
                          <v-select
                            :model-value="la.accountId"
                            :items="accountOptions"
                            item-title="text"
                            item-value="value"
                            density="compact"
                            variant="outlined"
                            hide-details
                            clearable
                            placeholder="Select account..."
                            @update:model-value="(val: string | null) => updateLinkedAccount(la, val)"
                          />
                        </td>
                        <td>
                          <v-switch
                            :model-value="la.isEnabled"
                            density="compact"
                            hide-details
                            color="primary"
                            @update:model-value="(val: boolean | null) => toggleLinkedAccount(la, val ?? false)"
                          />
                        </td>
                        <td class="text-body-2">{{ la.lastSyncAt ? new Date(la.lastSyncAt).toLocaleString() : 'Never' }}</td>
                      </tr>
                    </tbody>
                  </v-table>

                  <div class="d-flex align-center mt-3 ga-2">
                    <v-select
                      v-model="syncIntervals[conn.id]"
                      :items="intervalOptions"
                      item-title="text"
                      item-value="value"
                      label="Sync Interval"
                      density="compact"
                      variant="outlined"
                      hide-details
                      style="max-width: 200px"
                      @update:model-value="() => updateConnectionInterval(conn)"
                    />
                  </div>
                </v-expansion-panel-text>
              </v-expansion-panel>
            </v-expansion-panels>
          </v-tabs-window-item>
        </v-tabs-window>

        <!-- Account Mapping Dialog -->
        <v-dialog v-model="showMappingDialog" max-width="700" persistent>
          <v-card>
            <v-card-title>Map Bank Accounts</v-card-title>
            <v-card-text>
              <p class="mb-4">Map your external bank accounts to Purrse accounts, or auto-create new ones.</p>
              <v-table density="compact">
                <thead>
                  <tr>
                    <th>External Account</th>
                    <th>Type</th>
                    <th>Balance</th>
                    <th>Purrse Account</th>
                    <th>Auto-create</th>
                  </tr>
                </thead>
                <tbody>
                  <tr v-for="la in newLinkedAccounts" :key="la.id">
                    <td>{{ la.externalAccountName }}</td>
                    <td>{{ la.externalAccountType }}</td>
                    <td>{{ la.lastKnownBalance != null ? formatCurrency(la.lastKnownBalance) : '-' }}</td>
                    <td>
                      <v-select
                        v-model="mappingSelections[la.id]"
                        :items="accountOptions"
                        item-title="text"
                        item-value="value"
                        density="compact"
                        variant="outlined"
                        hide-details
                        clearable
                        :disabled="autoCreateSelections[la.id]"
                        placeholder="Select..."
                      />
                    </td>
                    <td>
                      <v-checkbox
                        v-model="autoCreateSelections[la.id]"
                        density="compact"
                        hide-details
                      />
                    </td>
                  </tr>
                </tbody>
              </v-table>
            </v-card-text>
            <v-card-actions>
              <v-spacer />
              <v-btn @click="showMappingDialog = false">Skip</v-btn>
              <v-btn color="primary" @click="saveMappings" :loading="mappingSaving">Save Mappings</v-btn>
            </v-card-actions>
          </v-card>
        </v-dialog>

        <!-- SimpleFIN Dialog -->
        <v-dialog v-model="showSimpleFinDialog" max-width="500">
          <v-card>
            <v-card-title>Connect via SimpleFIN</v-card-title>
            <v-card-text>
              <p class="mb-4">
                Visit <strong>beta-bridge.simplefin.org</strong> to get a setup token for your bank, then paste it below.
              </p>
              <v-text-field
                v-model="simpleFinToken"
                label="Setup Token"
                variant="outlined"
                placeholder="Paste your SimpleFIN setup token..."
              />
            </v-card-text>
            <v-card-actions>
              <v-spacer />
              <v-btn @click="showSimpleFinDialog = false">Cancel</v-btn>
              <v-btn color="primary" @click="connectSimpleFin" :loading="simpleFinLoading" :disabled="!simpleFinToken">
                Connect
              </v-btn>
            </v-card-actions>
          </v-card>
        </v-dialog>

        <!-- Delete Confirmation -->
        <v-dialog v-model="showDeleteDialog" max-width="400">
          <v-card>
            <v-card-title>Delete Connection</v-card-title>
            <v-card-text>
              Are you sure you want to delete the connection to <strong>{{ deleteTarget?.institutionName }}</strong>?
              This will remove all linked account mappings and sync history.
            </v-card-text>
            <v-card-actions>
              <v-spacer />
              <v-btn @click="showDeleteDialog = false">Cancel</v-btn>
              <v-btn color="error" @click="deleteConnection" :loading="deleteLoading">Delete</v-btn>
            </v-card-actions>
          </v-card>
        </v-dialog>

        <!-- Snackbars -->
        <v-snackbar v-model="showSyncResult" :timeout="5000" color="success">
          {{ syncResultMessage }}
        </v-snackbar>
        <v-snackbar v-model="showError" :timeout="6000" color="error">
          {{ errorMessage }}
        </v-snackbar>
      </v-tabs-window-item>

      <!-- Tab 3: Sync History -->
      <v-tabs-window-item value="history">
        <v-card>
          <v-card-title class="d-flex align-center">
            Sync History
            <v-spacer />
            <v-select
              v-model="logFilterConnectionId"
              :items="connectionFilterOptions"
              item-title="text"
              item-value="value"
              label="Filter by connection"
              density="compact"
              variant="outlined"
              hide-details
              clearable
              style="max-width: 300px"
              @update:model-value="loadSyncLogs"
            />
          </v-card-title>
          <v-data-table
            :headers="logHeaders"
            :items="syncLogs"
            :loading="logsLoading"
            density="compact"
            items-per-page="25"
          >
            <template v-slot:item.startedAt="{ item }">
              {{ new Date(item.startedAt).toLocaleString() }}
            </template>
            <template v-slot:item.status="{ item }">
              <v-chip
                :color="statusColor(item.status)"
                size="small"
              >
                {{ item.status }}
              </v-chip>
            </template>
            <template v-slot:item.duration="{ item }">
              {{ item.duration || '-' }}
            </template>
            <template v-slot:item.errorMessage="{ item }">
              <span v-if="item.errorMessage" class="text-error text-body-2">{{ item.errorMessage }}</span>
              <span v-else>-</span>
            </template>
          </v-data-table>
        </v-card>
      </v-tabs-window-item>

      <!-- Tab 4: AI -->
      <v-tabs-window-item value="ai">
        <v-alert type="info" variant="tonal" class="mb-4">
          AI features use a local Ollama LLM. Ollama runs locally on your machine — no data is sent to external services.
        </v-alert>

        <!-- Card 1: AI Configuration -->
        <v-card class="mb-4">
          <v-card-title>AI Configuration</v-card-title>
          <v-card-text>
            <v-row dense>
              <v-col cols="12" sm="6">
                <v-text-field
                  v-model="aiSettings.ollamaUrl"
                  label="Ollama URL"
                  variant="outlined"
                  density="compact"
                  placeholder="http://localhost:11434"
                />
              </v-col>
              <v-col cols="12" sm="6">
                <v-combobox
                  v-model="aiSettings.modelName"
                  :items="availableModels"
                  label="Model"
                  variant="outlined"
                  density="compact"
                  placeholder="llama3.1:8b"
                />
              </v-col>
            </v-row>

            <v-btn
              variant="tonal"
              color="secondary"
              :loading="aiTesting"
              @click="testAiConnection"
            >
              Test Connection
            </v-btn>

            <v-alert
              v-if="aiTestResult"
              :type="aiTestResult.success ? 'success' : 'error'"
              variant="tonal"
              class="mt-4"
              closable
              @click:close="aiTestResult = null"
            >
              <template v-if="aiTestResult.success">
                Connected to Ollama. Available models: {{ aiTestResult.availableModels?.join(', ') || 'none' }}
              </template>
              <template v-else>
                Connection failed: {{ aiTestResult.errorMessage }}
              </template>
            </v-alert>
          </v-card-text>
        </v-card>

        <!-- Card 2: AI Categorization -->
        <v-card class="mb-4">
          <v-card-title>AI Categorization</v-card-title>
          <v-card-text>
            <v-switch
              v-model="aiSettings.isEnabled"
              label="Enable AI Categorization"
              color="primary"
              hide-details
              class="mb-4"
              :disabled="!isOllamaConfigured"
            />

            <v-alert v-if="!isOllamaConfigured" type="warning" variant="tonal" class="mb-4">
              Configure Ollama connection above to enable AI features
            </v-alert>

            <v-row dense>
              <v-col cols="12" sm="6">
                <div class="text-body-2 mb-1">Confidence Threshold: {{ aiSettings.confidenceThreshold.toFixed(2) }}</div>
                <v-slider
                  v-model="aiSettings.confidenceThreshold"
                  :min="0.1"
                  :max="1.0"
                  :step="0.05"
                  thumb-label
                  color="primary"
                  hide-details
                />
              </v-col>
              <v-col cols="12" sm="6">
                <v-text-field
                  v-model.number="aiSettings.timeoutSeconds"
                  label="Timeout (seconds)"
                  variant="outlined"
                  density="compact"
                  type="number"
                  :min="5"
                  :max="120"
                />
              </v-col>
            </v-row>

            <v-checkbox
              v-model="aiSettings.updatePayeeDefaults"
              label="Auto-update payee default categories (learning loop)"
              color="primary"
              hide-details
              class="mb-4"
            />

            <v-divider class="mb-4" />

            <div class="text-subtitle-2 mb-2">Prompt Templates</div>
            <p class="text-body-2 text-medium-emphasis mb-4">
              Customize the prompts sent to the AI model. Use placeholders to control where dynamic data is inserted:
              <strong>{categories}</strong> = category list,
              <strong>{examples}</strong> = recent categorized transactions,
              <strong>{transactions}</strong> = uncategorized transactions to classify.
            </p>

            <v-textarea
              v-model="aiSettings.systemPrompt"
              label="System Prompt"
              variant="outlined"
              rows="8"
              class="mb-4"
            />

            <v-textarea
              v-model="aiSettings.userPromptTemplate"
              label="User Prompt Template"
              variant="outlined"
              rows="5"
              class="mb-4"
            />

            <v-btn
              variant="tonal"
              color="secondary"
              @click="resetPromptsToDefaults"
            >
              Reset to Defaults
            </v-btn>
          </v-card-text>
        </v-card>

        <!-- Card 3: AI Chat -->
        <v-card class="mb-4">
          <v-card-title>AI Chat</v-card-title>
          <v-card-text>
            <v-switch
              v-model="aiSettings.isChatEnabled"
              label="Enable AI Chat"
              color="primary"
              hide-details
              class="mb-4"
              :disabled="!isOllamaConfigured"
            />

            <v-alert v-if="!isOllamaConfigured" type="warning" variant="tonal" class="mb-4">
              Configure Ollama connection above to enable AI features
            </v-alert>

            <div class="text-body-2 mb-1">Context Size: {{ aiSettings.chatContextSize.toLocaleString() }} tokens</div>
            <v-slider
              v-model="aiSettings.chatContextSize"
              :min="2048"
              :max="131072"
              :step="2048"
              thumb-label
              color="primary"
              hide-details
              class="mb-1"
            />
            <div class="text-caption text-medium-emphasis mb-4">
              Estimated VRAM: ~{{ Math.round((aiSettings.chatContextSize / 1024) * 75) }} MB — Increase if the AI loses context in long chats. Decrease if Ollama runs out of memory.
            </div>

            <v-text-field
              v-model="aiSettings.chatBotName"
              label="Chatbot Name"
              variant="outlined"
              density="compact"
              placeholder="Purrse AI"
              hint="Custom name shown in the chat panel header and used by the AI"
              persistent-hint
              clearable
            />
          </v-card-text>
        </v-card>

        <v-btn
          color="primary"
          :loading="aiSaving"
          @click="saveAiSettings"
        >
          Save AI Settings
        </v-btn>

        <v-snackbar v-model="showAiSuccess" :timeout="4000" color="success">
          AI settings saved successfully
        </v-snackbar>
        <v-snackbar v-model="showAiError" :timeout="6000" color="error">
          {{ aiErrorMessage }}
        </v-snackbar>
      </v-tabs-window-item>
    </v-tabs-window>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted, onUnmounted, watch } from 'vue'
import { useRouter } from 'vue-router'
import { useAuthStore } from '@/stores/auth'
import { useNotifications } from '@/composables/useNotifications'
import { bankSyncApi } from '@/services/bankSync'
import { accountsApi } from '@/services/accounts'
import { aiCategorizationApi } from '@/services/aiCategorization'
import api from '@/services/api'
import type { SyncConnection, LinkedAccountInfo, Account, SyncLogEntry, PlaidCredentials, AiCategorizationSettings, OllamaConnectionTestResult, BankSyncNotification, UserProfile } from '@/types'

const authStore = useAuthStore()
const router = useRouter()

// UI state persistence
const SETTINGS_UI_KEY = 'purrse-settings-ui-state'

function loadUiState(): Record<string, any> | null {
  try {
    const stored = localStorage.getItem(SETTINGS_UI_KEY)
    return stored ? JSON.parse(stored) : null
  } catch { return null }
}

function saveUiState() {
  localStorage.setItem(SETTINGS_UI_KEY, JSON.stringify({
    settingsTab: activeTab.value,
    providerTab: activeProviderTab.value,
    expandedSimpleFin: expandedSimpleFinPanels.value,
    expandedPlaid: expandedPlaidPanels.value
  }))
}

const _savedUiState = loadUiState()
const activeTab = ref(_savedUiState?.settingsTab || 'profile')
const activeProviderTab = ref(_savedUiState?.providerTab || 'simplefin')
const expandedSimpleFinPanels = ref<string[]>(_savedUiState?.expandedSimpleFin || [])
const expandedPlaidPanels = ref<string[]>(_savedUiState?.expandedPlaid || [])

watch([activeTab, activeProviderTab, expandedSimpleFinPanels, expandedPlaidPanels], saveUiState, { deep: true })

// Profile
const profile = ref<UserProfile | null>(null)
const profileForm = reactive({ displayName: '', email: '' })
const passwordForm = reactive({ currentPassword: '', newPassword: '', confirmPassword: '' })
const profileSaving = ref(false)
const passwordChanging = ref(false)
const accountDeleting = ref(false)
const showDeleteAccountDialog = ref(false)
const showProfileSuccess = ref(false)
const profileSuccessMessage = ref('')
const showProfileError = ref(false)
const profileErrorMessage = ref('')

async function loadProfile() {
  try {
    const { data } = await api.get<UserProfile>('/auth/profile')
    profile.value = data
    profileForm.displayName = data.displayName || ''
    profileForm.email = data.email
  } catch (err: any) {
    profileErrorMessage.value = err.response?.data?.error || 'Failed to load profile'
    showProfileError.value = true
  }
}

async function saveProfile() {
  profileSaving.value = true
  try {
    const { data } = await api.put<UserProfile>('/auth/profile', {
      displayName: profileForm.displayName || null,
      email: profileForm.email
    })
    profile.value = data
    profileForm.displayName = data.displayName || ''
    profileForm.email = data.email
    authStore.setDisplayName(data.displayName)
    profileSuccessMessage.value = 'Profile updated'
    showProfileSuccess.value = true
  } catch (err: any) {
    profileErrorMessage.value = err.response?.data?.error || 'Failed to update profile'
    showProfileError.value = true
  } finally {
    profileSaving.value = false
  }
}

async function changePassword() {
  passwordChanging.value = true
  try {
    await api.post('/auth/change-password', {
      currentPassword: passwordForm.currentPassword,
      newPassword: passwordForm.newPassword
    })
    passwordForm.currentPassword = ''
    passwordForm.newPassword = ''
    passwordForm.confirmPassword = ''
    profileSuccessMessage.value = 'Password changed successfully'
    showProfileSuccess.value = true
  } catch (err: any) {
    profileErrorMessage.value = err.response?.data?.error || 'Failed to change password'
    showProfileError.value = true
  } finally {
    passwordChanging.value = false
  }
}

async function deleteAccount() {
  accountDeleting.value = true
  try {
    await api.delete('/auth/account')
    showDeleteAccountDialog.value = false
    authStore.logout()
    router.push('/login')
  } catch (err: any) {
    profileErrorMessage.value = err.response?.data?.error || 'Failed to delete account'
    showProfileError.value = true
  } finally {
    accountDeleting.value = false
  }
}

const loading = ref(false)
const connections = ref<SyncConnection[]>([])
const accounts = ref<Account[]>([])
const syncIntervals = reactive<Record<string, number>>({})
const syncingConnections = reactive<Record<string, boolean>>({})
const resyncingConnections = reactive<Record<string, boolean>>({})

// Provider-separated computed lists
const simpleFinConnections = computed(() =>
  connections.value.filter(c => c.provider === 'SimpleFIN')
)
const plaidConnections = computed(() =>
  connections.value.filter(c => c.provider === 'Plaid')
)

// Section-level loading states
const syncingAllSimpleFin = ref(false)
const resyncingAllSimpleFin = ref(false)
const syncingAllPlaid = ref(false)
const simpleFinGlobalInterval = ref(360)

// Plaid credentials
const plaidCredentials = ref<PlaidCredentials>({ isConfigured: false, environment: 'sandbox' })
const plaidForm = reactive({ clientId: '', secret: '', environment: 'sandbox' })
const plaidCredsSaving = ref(false)
const plaidEnvironments = ['sandbox', 'development', 'production']

// Plaid link
const plaidLoading = ref(false)

// SimpleFIN
const showSimpleFinDialog = ref(false)
const simpleFinToken = ref('')
const simpleFinLoading = ref(false)

// Mapping dialog
const showMappingDialog = ref(false)
const mappingSaving = ref(false)
const newConnectionId = ref('')
const newLinkedAccounts = ref<LinkedAccountInfo[]>([])
const mappingSelections = reactive<Record<string, string | null>>({})
const autoCreateSelections = reactive<Record<string, boolean>>({})

// Delete
const showDeleteDialog = ref(false)
const deleteTarget = ref<SyncConnection | null>(null)
const deleteLoading = ref(false)

// Sync result
const showSyncResult = ref(false)
const syncResultMessage = ref('')

// Error display
const showError = ref(false)
const errorMessage = ref('')

// Sync logs
const syncLogs = ref<SyncLogEntry[]>([])
const logsLoading = ref(false)
const logFilterConnectionId = ref<string | null>(null)

const accountOptions = computed(() =>
  accounts.value
    .filter(a => a.isActive && !a.isClosed)
    .map(a => ({ text: `${a.name} (${a.type})`, value: a.id }))
)

const connectionFilterOptions = computed(() =>
  connections.value.map(c => ({ text: c.institutionName, value: c.id }))
)

const intervalOptions = [
  { text: '1 hour', value: 60 },
  { text: '3 hours', value: 180 },
  { text: '6 hours', value: 360 },
  { text: '12 hours', value: 720 },
  { text: '24 hours', value: 1440 },
]

const logHeaders = [
  { title: 'Time', key: 'startedAt', sortable: true },
  { title: 'Institution', key: 'institutionName', sortable: true },
  { title: 'Account', key: 'linkedAccountName', sortable: false },
  { title: 'Status', key: 'status', sortable: true },
  { title: 'Imported', key: 'transactionsImported', sortable: false },
  { title: 'Skipped', key: 'transactionsSkipped', sortable: false },
  { title: 'Duration', key: 'duration', sortable: false },
  { title: 'Error', key: 'errorMessage', sortable: false },
]

function statusColor(status: string) {
  switch (status) {
    case 'Success': return 'success'
    case 'PartialSuccess': return 'warning'
    case 'Failed': return 'error'
    case 'Running': return 'info'
    default: return 'grey'
  }
}

function formatCurrency(value: number) {
  return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(value)
}

async function loadPlaidCredentials() {
  try {
    const { data } = await bankSyncApi.getPlaidCredentials()
    plaidCredentials.value = data
    plaidForm.environment = data.environment
  } catch {
    // Not configured yet
  }
}

async function savePlaidCredentials() {
  plaidCredsSaving.value = true
  try {
    const { data } = await bankSyncApi.savePlaidCredentials({
      clientId: plaidForm.clientId,
      secret: plaidForm.secret,
      environment: plaidForm.environment
    })
    plaidCredentials.value = data
    plaidForm.clientId = ''
    plaidForm.secret = ''
    syncResultMessage.value = 'Plaid credentials saved'
    showSyncResult.value = true
  } catch (err: any) {
    errorMessage.value = err.response?.data?.error || 'Failed to save Plaid credentials'
    showError.value = true
  } finally {
    plaidCredsSaving.value = false
  }
}

async function loadConnections() {
  loading.value = true
  try {
    const { data } = await bankSyncApi.getConnections()
    connections.value = data
    data.forEach(c => { syncIntervals[c.id] = c.syncIntervalMinutes })
    // Initialize global SimpleFIN interval from first SimpleFIN connection
    const firstSf = data.find(c => c.provider === 'SimpleFIN')
    if (firstSf) {
      simpleFinGlobalInterval.value = firstSf.syncIntervalMinutes
    }
  } finally {
    loading.value = false
  }
}

async function loadAccounts() {
  const { data } = await accountsApi.getAll()
  accounts.value = data
}

async function loadSyncLogs() {
  logsLoading.value = true
  try {
    const { data } = await bankSyncApi.getSyncLogs(logFilterConnectionId.value || undefined)
    syncLogs.value = data
  } finally {
    logsLoading.value = false
  }
}

async function startPlaidLink() {
  plaidLoading.value = true
  try {
    const { data: linkData } = await bankSyncApi.createLinkToken()

    if (!linkData.linkToken) {
      errorMessage.value = 'Plaid returned an empty link token. Check your Plaid credentials in appsettings.json.'
      showError.value = true
      plaidLoading.value = false
      return
    }

    // Dynamically load Plaid Link script
    await loadPlaidScript()

    const plaid = (window as any).Plaid.create({
      token: linkData.linkToken,
      onSuccess: async (publicToken: string) => {
        try {
          const { data: conn } = await bankSyncApi.completePlaidLink(publicToken)
          connections.value.unshift(conn)
          syncIntervals[conn.id] = conn.syncIntervalMinutes
          openMappingDialog(conn)
        } catch (err: any) {
          errorMessage.value = err.response?.data?.error || 'Failed to complete Plaid link'
          showError.value = true
        }
      },
      onExit: () => {
        plaidLoading.value = false
      }
    })
    plaid.open()
  } catch (err: any) {
    errorMessage.value = err.response?.data?.error || 'Failed to create Plaid link token. Check your Plaid credentials.'
    showError.value = true
    plaidLoading.value = false
  }
}

function loadPlaidScript(): Promise<void> {
  return new Promise((resolve, reject) => {
    if ((window as any).Plaid) {
      resolve()
      return
    }
    const script = document.createElement('script')
    script.src = 'https://cdn.plaid.com/link/v2/stable/link-initialize.js'
    script.onload = () => resolve()
    script.onerror = () => reject(new Error('Failed to load Plaid Link script'))
    document.head.appendChild(script)
  })
}

async function connectSimpleFin() {
  simpleFinLoading.value = true
  try {
    const { data: newConnections } = await bankSyncApi.connectSimpleFin(simpleFinToken.value)
    for (const conn of newConnections) {
      connections.value.unshift(conn)
      syncIntervals[conn.id] = conn.syncIntervalMinutes
    }
    showSimpleFinDialog.value = false
    simpleFinToken.value = ''
    if (newConnections.length > 0) {
      openMappingDialog(newConnections[0])
    }
  } catch (err: any) {
    errorMessage.value = err.response?.data?.error || 'Failed to connect via SimpleFIN. Check your setup token.'
    showError.value = true
  } finally {
    simpleFinLoading.value = false
  }
}

function openMappingDialog(conn: SyncConnection) {
  newConnectionId.value = conn.id
  newLinkedAccounts.value = conn.linkedAccounts
  conn.linkedAccounts.forEach(la => {
    mappingSelections[la.id] = null
    autoCreateSelections[la.id] = false
  })
  showMappingDialog.value = true
}

async function saveMappings() {
  mappingSaving.value = true
  try {
    for (const la of newLinkedAccounts.value) {
      const accountId = mappingSelections[la.id]
      const autoCreate = autoCreateSelections[la.id]
      if (accountId || autoCreate) {
        await bankSyncApi.linkAccount(newConnectionId.value, {
          linkedAccountId: la.id,
          accountId: autoCreate ? null : accountId,
          autoCreate
        })
      }
    }
    showMappingDialog.value = false
    await loadConnections()
    await loadAccounts()
  } finally {
    mappingSaving.value = false
  }
}

async function updateLinkedAccount(la: LinkedAccountInfo, accountId: string | null) {
  await bankSyncApi.updateLinkedAccount(la.id, { accountId, isEnabled: la.isEnabled })
  await loadConnections()
}

async function toggleLinkedAccount(la: LinkedAccountInfo, enabled: boolean) {
  await bankSyncApi.updateLinkedAccount(la.id, { accountId: la.accountId, isEnabled: enabled })
  await loadConnections()
}

async function updateConnectionInterval(conn: SyncConnection) {
  await bankSyncApi.updateConnection(conn.id, {
    isActive: conn.isActive,
    syncIntervalMinutes: syncIntervals[conn.id]
  })
}

async function toggleConnection(conn: SyncConnection) {
  await bankSyncApi.updateConnection(conn.id, {
    isActive: !conn.isActive,
    syncIntervalMinutes: conn.syncIntervalMinutes
  })
  await loadConnections()
}

async function syncNow(conn: SyncConnection) {
  syncingConnections[conn.id] = true
  try {
    await bankSyncApi.syncNow(conn.id)
  } catch (err: any) {
    syncingConnections[conn.id] = false
    errorMessage.value = err.response?.data?.error || 'Sync failed'
    showError.value = true
  }
}

async function resyncFromScratch(conn: SyncConnection) {
  resyncingConnections[conn.id] = true
  try {
    await bankSyncApi.resetSync(conn.id)
    await bankSyncApi.syncNow(conn.id)
    syncingConnections[conn.id] = true
  } catch (err: any) {
    errorMessage.value = err.response?.data?.error || 'Re-sync failed'
    showError.value = true
  } finally {
    resyncingConnections[conn.id] = false
  }
}

async function syncAllSimpleFin() {
  const active = simpleFinConnections.value.filter(c => c.isActive)
  if (active.length === 0) return
  syncingAllSimpleFin.value = true
  try {
    for (const conn of active) {
      syncingConnections[conn.id] = true
      await bankSyncApi.syncNow(conn.id)
    }
  } catch (err: any) {
    errorMessage.value = err.response?.data?.error || 'SimpleFIN sync failed'
    showError.value = true
  }
}

async function resyncAllSimpleFin() {
  const active = simpleFinConnections.value.filter(c => c.isActive)
  if (active.length === 0) return
  resyncingAllSimpleFin.value = true
  try {
    for (const conn of active) {
      await bankSyncApi.resetSync(conn.id)
      syncingConnections[conn.id] = true
      await bankSyncApi.syncNow(conn.id)
    }
  } catch (err: any) {
    errorMessage.value = err.response?.data?.error || 'SimpleFIN re-sync failed'
    showError.value = true
  } finally {
    resyncingAllSimpleFin.value = false
  }
}

async function syncAllPlaid() {
  const active = plaidConnections.value.filter(c => c.isActive)
  if (active.length === 0) return
  syncingAllPlaid.value = true
  try {
    for (const conn of active) {
      syncingConnections[conn.id] = true
      await bankSyncApi.syncNow(conn.id)
    }
  } catch (err: any) {
    errorMessage.value = err.response?.data?.error || 'Plaid sync failed'
    showError.value = true
  }
}

async function updateSimpleFinGlobalInterval() {
  try {
    for (const conn of simpleFinConnections.value) {
      syncIntervals[conn.id] = simpleFinGlobalInterval.value
      await bankSyncApi.updateConnection(conn.id, {
        isActive: conn.isActive,
        syncIntervalMinutes: simpleFinGlobalInterval.value
      })
    }
  } catch (err: any) {
    errorMessage.value = err.response?.data?.error || 'Failed to update sync interval'
    showError.value = true
  }
}

// Handle sync results via SignalR notification
const { notifications } = useNotifications()
watch(notifications, (notifs) => {
  const latest = notifs[0]
  if (latest && !latest.read && latest.type === 'BankSyncComplete') {
    const data = latest.data as BankSyncNotification
    syncingConnections[data.connectionId] = false
    syncResultMessage.value = `Synced ${data.institutionName}: ${data.transactionsImported} imported, ${data.transactionsSkipped} skipped`
    showSyncResult.value = true
    loadConnections()

    // Clear section-level loading if all connections in the group are done
    if (syncingAllSimpleFin.value) {
      const stillSyncing = simpleFinConnections.value.some(c => syncingConnections[c.id])
      if (!stillSyncing) syncingAllSimpleFin.value = false
    }
    if (syncingAllPlaid.value) {
      const stillSyncing = plaidConnections.value.some(c => syncingConnections[c.id])
      if (!stillSyncing) syncingAllPlaid.value = false
    }
  }
})

function confirmDeleteConnection(conn: SyncConnection) {
  deleteTarget.value = conn
  showDeleteDialog.value = true
}

async function deleteConnection() {
  if (!deleteTarget.value) return
  deleteLoading.value = true
  try {
    await bankSyncApi.deleteConnection(deleteTarget.value.id)
    connections.value = connections.value.filter(c => c.id !== deleteTarget.value!.id)
    showDeleteDialog.value = false
  } finally {
    deleteLoading.value = false
  }
}

// AI Categorization
const aiSettings = reactive<AiCategorizationSettings>({
  isEnabled: false,
  ollamaUrl: 'http://localhost:11434',
  modelName: 'llama3.1:8b',
  confidenceThreshold: 0.7,
  timeoutSeconds: 30,
  updatePayeeDefaults: true,
  isChatEnabled: false,
  systemPrompt: null,
  userPromptTemplate: null,
  chatContextSize: 16384,
  chatBotName: null
})

const isOllamaConfigured = computed(() =>
  !!aiSettings.ollamaUrl?.trim() && !!aiSettings.modelName?.trim()
)
const aiSaving = ref(false)
const aiTesting = ref(false)
const aiTestResult = ref<OllamaConnectionTestResult | null>(null)
const availableModels = ref<string[]>([])
const showAiSuccess = ref(false)
const showAiError = ref(false)
const aiErrorMessage = ref('')

const defaultSystemPrompt = `You are a personal finance transaction categorizer. Classify each transaction into the most appropriate category.

You MUST respond with valid JSON in exactly this format:
{
  "classifications": [
    {"index": 0, "categoryName": "Groceries", "confidence": 0.9},
    {"index": 1, "categoryName": "Utilities", "confidence": 0.85}
  ]
}

Rules:
- "index" must be the transaction number (integer) from the list below
- "categoryName" must be one of the exact category names listed below
- "confidence" must be a number between 0 and 1
- Include one entry for every transaction

Available categories:
{categories}`

const defaultUserPromptTemplate = `{examples}Classify these uncategorized transactions:
{transactions}`

function resetPromptsToDefaults() {
  aiSettings.systemPrompt = defaultSystemPrompt
  aiSettings.userPromptTemplate = defaultUserPromptTemplate
}

async function loadAiSettings() {
  try {
    const { data } = await aiCategorizationApi.getSettings()
    Object.assign(aiSettings, data)
    aiSettings.systemPrompt = aiSettings.systemPrompt || defaultSystemPrompt
    aiSettings.userPromptTemplate = aiSettings.userPromptTemplate || defaultUserPromptTemplate
  } catch {
    // Not configured yet — defaults are fine
    aiSettings.systemPrompt = defaultSystemPrompt
    aiSettings.userPromptTemplate = defaultUserPromptTemplate
  }
}

async function saveAiSettings() {
  aiSaving.value = true
  try {
    const { data } = await aiCategorizationApi.updateSettings({ ...aiSettings })
    Object.assign(aiSettings, data)
    showAiSuccess.value = true
  } catch (err: any) {
    aiErrorMessage.value = err.response?.data?.error || 'Failed to save AI settings'
    showAiError.value = true
  } finally {
    aiSaving.value = false
  }
}

async function testAiConnection() {
  aiTesting.value = true
  aiTestResult.value = null
  try {
    const { data } = await aiCategorizationApi.testConnection()
    aiTestResult.value = data
    if (data.availableModels && data.availableModels.length > 0) {
      availableModels.value = data.availableModels
    }
  } catch (err: any) {
    aiTestResult.value = { success: false, errorMessage: err.response?.data?.error || 'Connection test failed', availableModels: null }
  } finally {
    aiTesting.value = false
  }
}

onMounted(async () => {
  await Promise.all([loadProfile(), loadPlaidCredentials(), loadConnections(), loadAccounts(), loadSyncLogs(), loadAiSettings()])
})
</script>
