import { Ionicons } from '@expo/vector-icons';
import { Directory, File, Paths } from 'expo-file-system';
import * as Sharing from 'expo-sharing';
import { useState } from 'react';
import { StyleSheet, View, TouchableOpacity } from 'react-native';

import type { Item } from '@/utils/dist/core/models/vault';
import { getFieldValue } from '@/utils/dist/core/models/vault';
import { VaultUnlockHelper } from '@/utils/VaultUnlockHelper';

import { useColors } from '@/hooks/useColorScheme';
import { useTranslation } from '@/hooks/useTranslation';

import LoadingOverlay from '@/components/LoadingOverlay';
import { ThemedContainer } from '@/components/themed/ThemedContainer';
import { ThemedScrollView } from '@/components/themed/ThemedScrollView';
import { ThemedText } from '@/components/themed/ThemedText';
import { useDb } from '@/context/DbContext';
import { useDialog } from '@/context/DialogContext';

/**
 * CSV record for Item objects (matching server ItemCsvRecord format).
 * Must match the column order and types from AliasVault.ImportExport.ItemCsvService.
 */
interface IItemCsvRecord {
  ServiceName: string;
  FolderPath: string;
  ServiceUrl: string;
  Username: string;
  CurrentPassword: string;
  AliasEmail: string;
  TwoFactorSecret: string;
  AliasGender: string;
  AliasFirstName: string;
  AliasLastName: string;
  AliasNickName: string;
  AliasBirthDate: string;
  CardholderName: string;
  CardNumber: string;
  CardExpiryMonth: string;
  CardExpiryYear: string;
  CardCvv: string;
  CardPin: string;
  Notes: string;
  CreatedAt: string;
  UpdatedAt: string;
}

/**
 * Import/Export settings screen.
 * @returns The Import/Export settings screen component.
 */
export default function ImportExportScreen(): React.ReactNode {
  const colors = useColors();
  const { t } = useTranslation();
  const dbContext = useDb();
  const { showAlert, showConfirm } = useDialog();
  const [isExporting, setIsExporting] = useState(false);

  /**
   * Format date to match server format (MM/DD/YYYY HH:mm:ss).
   */
  const formatDate = (dateStr: string | null | undefined): string => {
    if (!dateStr) {
      const now = new Date();
      const month = String(now.getMonth() + 1).padStart(2, '0');
      const day = String(now.getDate()).padStart(2, '0');
      const year = now.getFullYear();
      const hours = String(now.getHours()).padStart(2, '0');
      const minutes = String(now.getMinutes()).padStart(2, '0');
      const seconds = String(now.getSeconds()).padStart(2, '0');
      return `${month}/${day}/${year} ${hours}:${minutes}:${seconds}`;
    }

    try {
      const date = new Date(dateStr);
      if (isNaN(date.getTime())) {
        // If invalid date, return empty string
        return '';
      }
      const month = String(date.getMonth() + 1).padStart(2, '0');
      const day = String(date.getDate()).padStart(2, '0');
      const year = date.getFullYear();
      const hours = String(date.getHours()).padStart(2, '0');
      const minutes = String(date.getMinutes()).padStart(2, '0');
      const seconds = String(date.getSeconds()).padStart(2, '0');
      return `${month}/${day}/${year} ${hours}:${minutes}:${seconds}`;
    } catch {
      // Return empty string if parsing fails
      return '';
    }
  };

  /**
   * Helper to extract a single string value from field (handles string | string[] return type).
   */
  const getFieldValueAsString = (item: Item, fieldKey: string): string => {
    const value = getFieldValue(item, fieldKey);
    if (Array.isArray(value)) {
      return value[0] ?? '';
    }
    return value ?? '';
  };

  /**
   * Convert items to CSV format.
   * Matches the server's ItemCsvService.ExportItemsToCsv format.
   */
  const itemsToCsv = async (items: Item[]): Promise<string> => {
    const records: IItemCsvRecord[] = [];

    /*
     * Get all items with their TOTP codes
     */
    for (const item of items) {
      // Get TOTP codes for this item
      const totpCodes = await dbContext.sqliteClient?.settings.getTotpCodesForItem(item.Id) ?? [];
      const totpSecret = totpCodes.length > 0 ? totpCodes[0].SecretKey : '';

      /*
       * Build folder path (hierarchical with "/" separator)
       * FolderPath is an array like ["Work", "Projects", "Active"]
       */
      const folderPath = item.FolderPath?.join('/') ?? '';

      // Get field values using the same FieldKey constants as server
      const serviceUrl = getFieldValueAsString(item, 'login.url');
      const username = getFieldValueAsString(item, 'login.username');
      const password = getFieldValueAsString(item, 'login.password');
      const aliasEmail = getFieldValueAsString(item, 'login.email');
      const aliasGender = getFieldValueAsString(item, 'alias.gender');
      const aliasFirstName = getFieldValueAsString(item, 'alias.firstName');
      const aliasLastName = getFieldValueAsString(item, 'alias.lastName');
      const aliasBirthdate = getFieldValueAsString(item, 'alias.birthdate');
      const notes = getFieldValueAsString(item, 'notes.content');
      const cardholderName = getFieldValueAsString(item, 'card.cardholder_name');
      const cardNumber = getFieldValueAsString(item, 'card.number');
      const cardExpiryMonth = getFieldValueAsString(item, 'card.expiry_month');
      const cardExpiryYear = getFieldValueAsString(item, 'card.expiry_year');
      const cardCvv = getFieldValueAsString(item, 'card.cvv');
      const cardPin = getFieldValueAsString(item, 'card.pin');

      // Parse birthdate to formatted string (server expects MM/DD/YYYY format in CSV)
      const formattedBirthDate = aliasBirthdate ? formatDate(aliasBirthdate) : '';

      const record: IItemCsvRecord = {
        ServiceName: item.Name ?? '',
        FolderPath: folderPath,
        ServiceUrl: serviceUrl,
        Username: username,
        CurrentPassword: password,
        AliasEmail: aliasEmail,
        TwoFactorSecret: totpSecret,
        AliasGender: aliasGender,
        AliasFirstName: aliasFirstName,
        AliasLastName: aliasLastName,
        AliasNickName: '', // NickName is no longer stored as a separate field
        AliasBirthDate: formattedBirthDate,
        CardholderName: cardholderName,
        CardNumber: cardNumber,
        CardExpiryMonth: cardExpiryMonth,
        CardExpiryYear: cardExpiryYear,
        CardCvv: cardCvv,
        CardPin: cardPin,
        Notes: notes,
        CreatedAt: formatDate(item.CreatedAt),
        UpdatedAt: formatDate(item.UpdatedAt)
      };

      records.push(record);
    }

    // Generate CSV header (matching server format)
    const headers = [
      'ServiceName',
      'FolderPath',
      'ServiceUrl',
      'Username',
      'CurrentPassword',
      'AliasEmail',
      'TwoFactorSecret',
      'AliasGender',
      'AliasFirstName',
      'AliasLastName',
      'AliasNickName',
      'AliasBirthDate',
      'CardholderName',
      'CardNumber',
      'CardExpiryMonth',
      'CardExpiryYear',
      'CardCvv',
      'CardPin',
      'Notes',
      'CreatedAt',
      'UpdatedAt'
    ];

    /**
     * Escape CSV value.
     * @param {string} value - The value to escape.
     * @returns {string} The escaped value.
     */
    const escapeCsvValue = (value: string): string => {
      // If value contains comma, newline, or quote, wrap in quotes
      if (value.includes(',') || value.includes('\n') || value.includes('"') || value.includes('\r')) {
        // Escape quotes by doubling them and wrap in quotes
        return `"${value.replace(/"/g, '""')}"`;
      }
      return value;
    };

    // Generate CSV content
    const csvLines: string[] = [headers.join(',')];

    for (const record of records) {
      const values = [
        escapeCsvValue(record.ServiceName),
        escapeCsvValue(record.FolderPath),
        escapeCsvValue(record.ServiceUrl),
        escapeCsvValue(record.Username),
        escapeCsvValue(record.CurrentPassword),
        escapeCsvValue(record.AliasEmail),
        escapeCsvValue(record.TwoFactorSecret),
        escapeCsvValue(record.AliasGender),
        escapeCsvValue(record.AliasFirstName),
        escapeCsvValue(record.AliasLastName),
        escapeCsvValue(record.AliasNickName),
        escapeCsvValue(record.AliasBirthDate),
        escapeCsvValue(record.CardholderName),
        escapeCsvValue(record.CardNumber),
        escapeCsvValue(record.CardExpiryMonth),
        escapeCsvValue(record.CardExpiryYear),
        escapeCsvValue(record.CardCvv),
        escapeCsvValue(record.CardPin),
        escapeCsvValue(record.Notes),
        escapeCsvValue(record.CreatedAt),
        escapeCsvValue(record.UpdatedAt)
      ];
      csvLines.push(values.join(','));
    }

    return csvLines.join('\n');
  };

  /**
   * Show export confirmation dialog, then password verification.
   */
  const showExportConfirmation = (): void => {
    showConfirm(
      t('settings.exportConfirmTitle'),
      t('settings.exportWarning'),
      t('common.confirm'),
      async () => {
        try {
          /*
           * Request password authentication using native unlock screen
           * Only allow password method (no biometric or PIN) for sensitive export operation
           */
          const authenticated = await VaultUnlockHelper.authenticateForAction(
            t('settings.exportConfirmTitle'),
            t('settings.passwordConfirm.exportDescription'),
            ['password'], // Only allow password authentication
            t('common.confirm')
          );

          if (!authenticated) {
            // User cancelled or authentication failed
            return;
          }

          // Password verified, proceed with export
          await handleExport();
        } catch (error) {
          console.error('Authentication error during CSV export:', error);
          showAlert(t('common.error'), t('common.errors.unknownError'));
        }
      },
      { confirmStyle: 'destructive' }
    );
  };

  /**
   * Handle the CSV export.
   */
  const handleExport = async (): Promise<void> => {
    if (isExporting) {
      return;
    }

    /*
     * Note: when updating this CSV export logic, make sure to update the
     * unittest "ImportCredentialsFromAliasVaultMobileAppCsv" in the .NET solution as well.
     */

    setIsExporting(true);

    try {
      const dateStr = new Date().toISOString().split('T')[0];

      // Export as CSV
      const items = await dbContext.sqliteClient?.items.getAll() ?? [];
      const csvContent = await itemsToCsv(items);

      const filename = `aliasvault-export-${dateStr}.csv`;
      const downloadsDir = new Directory(Paths.document, 'Exports');
      if (!downloadsDir.exists) {
        downloadsDir.create({ intermediates: true });
      }

      const file = new File(downloadsDir, filename);
      if (file.exists) {
        file.delete();
      }
      file.create();
      file.write(csvContent);

      // Share the file using the system share dialog
      const canShare = await Sharing.isAvailableAsync();
      if (canShare) {
        await Sharing.shareAsync(file.uri, {
          dialogTitle: filename,
          mimeType: 'text/csv',
        });

        // Clean up the temporary file after sharing
        setTimeout(() => {
          try {
            if (file.exists) {
              file.delete();
            }
          } catch (error) {
            console.error('Error cleaning up export file:', error);
          }
        }, 5000);
      }
    } catch (error) {
      console.error('Export error:', error);
      showAlert(t('common.error'), t('common.errors.unknownError'));
    } finally {
      setIsExporting(false);
    }
  };

  const styles = StyleSheet.create({
    button: {
      alignItems: 'center',
      backgroundColor: colors.primary,
      borderRadius: 8,
      flexDirection: 'row',
      justifyContent: 'center',
      marginVertical: 8,
      paddingHorizontal: 16,
      paddingVertical: 12,
    },
    buttonDisabled: {
      opacity: 0.5,
    },
    buttonText: {
      color: colors.primarySurfaceText,
      fontSize: 16,
      fontWeight: '600',
      marginLeft: 8,
    },
    importNote: {
      backgroundColor: colors.tertiary + '20', // Use tertiary color with opacity
      borderRadius: 8,
      marginTop: 8,
      padding: 12,
    },
    importNoteText: {
      color: colors.text,
      fontSize: 14,
      lineHeight: 20,
    },
    section: {
      backgroundColor: colors.accentBackground,
      borderRadius: 10,
      marginTop: 16,
      padding: 16,
    },
    sectionDescription: {
      color: colors.textMuted,
      fontSize: 14,
      lineHeight: 20,
      marginBottom: 16,
    },
    sectionTitle: {
      color: colors.text,
      fontSize: 18,
      fontWeight: '600',
      marginBottom: 8,
    },
  });

  return (
    <>
      {isExporting && (
        <LoadingOverlay status={t('settings.exporting')} />
      )}
      <ThemedContainer>
        <ThemedScrollView>
          {/* Import Section */}
          <View style={styles.section}>
            <ThemedText style={styles.sectionTitle}>
              {t('settings.importSectionTitle')}
            </ThemedText>
            <ThemedText style={styles.sectionDescription}>
              {t('settings.importSectionDescription')}
            </ThemedText>
            <View style={styles.importNote}>
              <ThemedText style={styles.importNoteText}>
                {t('settings.importWebNote')}
              </ThemedText>
            </View>
          </View>

          {/* Export Section */}
          <View style={styles.section}>
            <ThemedText style={styles.sectionTitle}>
              {t('settings.exportSectionTitle')}
            </ThemedText>
            <ThemedText style={styles.sectionDescription}>
              {t('settings.exportSectionDescription')}
            </ThemedText>

            <TouchableOpacity
              style={[styles.button, isExporting && styles.buttonDisabled]}
              onPress={() => showExportConfirmation()}
              disabled={isExporting}
            >
              <Ionicons name="document-text" size={20} color={colors.primarySurfaceText} />
              <ThemedText style={styles.buttonText}>
                {isExporting
                  ? (t('settings.exporting'))
                  : (t('settings.exportCsvButton'))
                }
              </ThemedText>
            </TouchableOpacity>
          </View>
        </ThemedScrollView>
      </ThemedContainer>
    </>
  );
}
