// ========================================
// Citizenship Workflow Library
// ========================================
// Handles citizenship verification, status checks, and workflow logic

import type { ApiPromise } from '@pezkuwi/api';
// Temporarily disabled for React Native compatibility
// import { web3FromAddress } from '@pezkuwi/extension-dapp';
import type { InjectedAccountWithMeta } from '@pezkuwi/extension-inject/types';

import type { Signer } from '@pezkuwi/api/types';

interface SignRawPayload {
  address: string;
  data: string;
  type: string;
}

interface SignRawResult {
  signature: string;
}

interface InjectedSigner {
  signRaw?: (payload: SignRawPayload) => Promise<SignRawResult>;
}

interface InjectedExtension {
  signer: Signer & InjectedSigner;
}

// Stub for mobile - TODO: implement proper React Native version
const web3FromAddress = async (_address: string): Promise<InjectedExtension> => {
  // In React Native, we'll use a different signing mechanism
  throw new Error('web3FromAddress not implemented for React Native yet');
};

// ========================================
// TYPE DEFINITIONS
// ========================================

export type KycStatus = 'NotStarted' | 'Pending' | 'Approved' | 'Rejected';

export type Region =
  | 'bakur'       // North (Turkey)
  | 'basur'       // South (Iraq)
  | 'rojava'      // West (Syria)
  | 'rojhelat'    // East (Iran)
  | 'diaspora'    // Diaspora
  | 'kurdistan_a_sor'; // Red Kurdistan (Armenia/Azerbaijan)

export type MaritalStatus = 'zewici' | 'nezewici'; // Married / Unmarried

export interface ChildInfo {
  name: string;
  birthYear: number;
}

export interface CitizenshipData {
  // Personal Identity
  fullName: string;
  fatherName: string;
  grandfatherName: string;
  motherName: string;

  // Tribal Affiliation
  tribe: string;

  // Family Status
  maritalStatus: MaritalStatus;
  childrenCount?: number;
  children?: ChildInfo[];

  // Geographic Origin
  region: Region;

  // Contact & Profession
  email: string;
  profession: string;

  // Referral
  referralCode?: string;

  // Metadata
  walletAddress: string;
  timestamp: number;
}

export interface CitizenshipCommitment {
  commitmentHash: string;    // SHA256 hash of all data
  nullifierHash: string;      // Prevents double-registration
  ipfsCid: string;            // IPFS CID of encrypted data
  publicKey: string;          // User's encryption public key
  timestamp: number;
}

export interface TikiInfo {
  id: string;
  role: string;
  metadata?: any;
}

export interface CitizenshipStatus {
  kycStatus: KycStatus;
  hasCitizenTiki: boolean;
  tikiNumber?: string;
  stakingScoreTracking: boolean;
  ipfsCid?: string;
  nextAction: 'APPLY_KYC' | 'CLAIM_TIKI' | 'START_TRACKING' | 'COMPLETE';
}

// ========================================
// KYC STATUS CHECKS
// ========================================

/**
 * Get KYC status for a wallet address
 */
export async function getKycStatus(
  api: ApiPromise,
  address: string
): Promise<KycStatus> {
  try {
    // MOCK FOR DEV: Alice is Approved
    if (address === '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY') {
      return 'Approved';
    }

    if (!api?.query?.identityKyc) {
      console.warn('Identity KYC pallet not available');
      return 'NotStarted';
    }

    const status = await api.query.identityKyc.kycStatuses(address);

    if (status.isEmpty) {
      return 'NotStarted';
    }

    const statusStr = status.toString();

    // Map on-chain status to our type
    if (statusStr === 'Approved') return 'Approved';
    if (statusStr === 'Pending') return 'Pending';
    if (statusStr === 'Rejected') return 'Rejected';

    return 'NotStarted';
  } catch (error) {
    console.error('Error fetching KYC status:', error);
    return 'NotStarted';
  }
}

/**
 * Check if user has pending KYC application
 */
export async function hasPendingApplication(
  api: ApiPromise,
  address: string
): Promise<boolean> {
  try {
    if (!api?.query?.identityKyc?.pendingKycApplications) {
      return false;
    }

    const application = await api.query.identityKyc.pendingKycApplications(address);
    return !application.isEmpty;
  } catch (error) {
    console.error('Error checking pending application:', error);
    return false;
  }
}

// ========================================
// TIKI / CITIZENSHIP CHECKS
// ========================================

/**
 * Get all Tiki roles for a user
 */
// Tiki enum mapping from pallet-tiki
// IMPORTANT: Must match exact order in /Pezkuwi-SDK/pezkuwi/pallets/tiki/src/lib.rs
const TIKI_ROLES = [
  'Welati', 'Parlementer', 'SerokiMeclise', 'Serok', 'Wezir', 'EndameDiwane', 'Dadger',
  'Dozger', 'Hiquqnas', 'Noter', 'Xezinedar', 'Bacgir', 'GerinendeyeCavkaniye', 'OperatorêTorê',
  'PisporêEwlehiyaSîber', 'GerinendeyeDaneye', 'Berdevk', 'Qeydkar', 'Balyoz', 'Navbeynkar',
  'ParêzvaneÇandî', 'Mufetîs', 'KalîteKontrolker', 'Mela', 'Feqî', 'Perwerdekar', 'Rewsenbîr',
  'RêveberêProjeyê', 'SerokêKomele', 'ModeratorêCivakê', 'Axa', 'Pêseng', 'Sêwirmend', 'Hekem', 'Mamoste',
  'Bazargan',
  'SerokWeziran', 'WezireDarayiye', 'WezireParez', 'WezireDad', 'WezireBelaw', 'WezireTend', 'WezireAva', 'WezireCand'
];

export async function getUserTikis(
  api: ApiPromise,
  address: string
): Promise<TikiInfo[]> {
  try {
    if (!api?.query?.tiki?.userTikis) {
      console.warn('Tiki pallet not available');
      return [];
    }

    const tikis = await api.query.tiki.userTikis(address);

    if (tikis.isEmpty) {
      return [];
    }

    // userTikis returns a BoundedVec of Tiki enum values (as indices)
    const tikiIndices = tikis.toJSON() as number[];

    return tikiIndices.map((index, i) => ({
      id: `${index}`,
      role: TIKI_ROLES[index] || `Unknown Role (${index})`,
      metadata: {}
    }));
  } catch (error) {
    console.error('Error fetching user tikis:', error);
    return [];
  }
}

/**
 * Check if user has Welati (Citizen) Tiki
 * Blockchain uses "Welati" as the actual role name
 */
export async function hasCitizenTiki(
  api: ApiPromise,
  address: string
): Promise<{ hasTiki: boolean; tikiNumber?: string }> {
  try {
    const tikis = await getUserTikis(api, address);

    const citizenTiki = tikis.find(t =>
      t.role.toLowerCase() === 'welati' ||
      t.role.toLowerCase() === 'citizen'
    );

    return {
      hasTiki: !!citizenTiki,
      tikiNumber: citizenTiki?.id
    };
  } catch (error) {
    console.error('Error checking citizen tiki:', error);
    return { hasTiki: false };
  }
}

/**
 * Verify NFT ownership by NFT number
 */
export async function verifyNftOwnership(
  api: ApiPromise,
  nftNumber: string,
  walletAddress: string
): Promise<boolean> {
  try {
    const tikis = await getUserTikis(api, walletAddress);

    return tikis.some(tiki =>
      tiki.id === nftNumber &&
      (
        tiki.role.toLowerCase() === 'welati' ||
        tiki.role.toLowerCase() === 'citizen'
      )
    );
  } catch (error) {
    console.error('Error verifying NFT ownership:', error);
    return false;
  }
}

// ========================================
// STAKING SCORE TRACKING
// ========================================

/**
 * Check if staking score tracking has been started
 */
export async function isStakingScoreTracking(
  api: ApiPromise,
  address: string
): Promise<boolean> {
  try {
    if (!api?.query?.stakingScore?.stakingStartBlock) {
      console.warn('Staking score pallet not available');
      return false;
    }

    const startBlock = await api.query.stakingScore.stakingStartBlock(address) as any;
    return !startBlock.isNone;
  } catch (error) {
    console.error('Error checking staking score tracking:', error);
    return false;
  }
}

/**
 * Check if user is staking
 */
export async function isStaking(
  api: ApiPromise,
  address: string
): Promise<boolean> {
  try {
    if (!api?.query?.staking?.ledger) {
      return false;
    }

    const ledger = await api.query.staking.ledger(address) as any;
    return !ledger.isNone;
  } catch (error) {
    console.error('Error checking staking status:', error);
    return false;
  }
}

// ========================================
// COMPREHENSIVE CITIZENSHIP STATUS
// ========================================

/**
 * Get complete citizenship status and next action needed
 */
export async function getCitizenshipStatus(
  api: ApiPromise,
  address: string
): Promise<CitizenshipStatus> {
  try {
    if (!api || !address) {
      return {
        kycStatus: 'NotStarted',
        hasCitizenTiki: false,
        stakingScoreTracking: false,
        nextAction: 'APPLY_KYC'
      };
    }

    // Fetch all status in parallel
    const [kycStatus, citizenCheck, stakingTracking] = await Promise.all([
      getKycStatus(api, address),
      hasCitizenTiki(api, address),
      isStakingScoreTracking(api, address)
    ]);

    const kycApproved = kycStatus === 'Approved';
    const hasTiki = citizenCheck.hasTiki;

    // Determine next action
    let nextAction: CitizenshipStatus['nextAction'];

    if (!kycApproved) {
      nextAction = 'APPLY_KYC';
    } else if (!hasTiki) {
      nextAction = 'CLAIM_TIKI';
    } else if (!stakingTracking) {
      nextAction = 'START_TRACKING';
    } else {
      nextAction = 'COMPLETE';
    }

    return {
      kycStatus,
      hasCitizenTiki: hasTiki,
      tikiNumber: citizenCheck.tikiNumber,
      stakingScoreTracking: stakingTracking,
      nextAction
    };
  } catch (error) {
    console.error('Error fetching citizenship status:', error);
    return {
      kycStatus: 'NotStarted',
      hasCitizenTiki: false,
      stakingScoreTracking: false,
      nextAction: 'APPLY_KYC'
    };
  }
}

// ========================================
// IPFS COMMITMENT RETRIEVAL
// ========================================

/**
 * Get IPFS CID for citizen data
 */
export async function getCitizenDataCid(
  api: ApiPromise,
  address: string
): Promise<string | null> {
  try {
    if (!api?.query?.identityKyc?.identities) {
      return null;
    }

    // Try to get from identity storage
    // This assumes the pallet stores IPFS CID somewhere
    // Adjust based on actual pallet storage structure
    const identity = await api.query.identityKyc.identities(address) as any;

    if (identity.isNone) {
      return null;
    }

    const identityData = identity.unwrap().toJSON() as any;

    // Try different possible field names
    return identityData.ipfsCid ||
           identityData.cid ||
           identityData.dataCid ||
           null;
  } catch (error) {
    console.error('Error fetching citizen data CID:', error);
    return null;
  }
}

// ========================================
// REFERRAL VALIDATION
// ========================================

/**
 * Validate referral code
 */
export async function validateReferralCode(
  api: ApiPromise,
  referralCode: string
): Promise<boolean> {
  try {
    if (!referralCode || referralCode.trim() === '') {
      return true; // Empty is valid (will use founder)
    }

    // Check if referral code exists in trust pallet
    if (!api?.query?.trust?.referrals) {
      return false;
    }

    // Referral code could be an address or custom code
    // For now, check if it's a valid address format
    // TODO: Implement proper referral code lookup

    return referralCode.length > 0;
  } catch (error) {
    console.error('Error validating referral code:', error);
    return false;
  }
}

// ========================================
// BLOCKCHAIN TRANSACTIONS
// ========================================

/**
 * Submit KYC application to blockchain
 * This is a two-step process:
 * 1. Set identity (name, email)
 * 2. Apply for KYC (IPFS CID, notes)
 */
export async function submitKycApplication(
  api: ApiPromise,
  account: InjectedAccountWithMeta,
  name: string,
  email: string,
  ipfsCid: string,
  notes: string = 'Citizenship application'
): Promise<{ success: boolean; error?: string; blockHash?: string }> {
  try {
    if (!api?.tx?.identityKyc?.setIdentity || !api?.tx?.identityKyc?.applyForKyc) {
      return { success: false, error: 'Identity KYC pallet not available' };
    }

    // Check if user already has a pending KYC application
    const pendingApp = await api.query.identityKyc.pendingKycApplications(account.address);
    if (!pendingApp.isEmpty) {
      console.log('⚠️ User already has a pending KYC application');
      return {
        success: false,
        error: 'You already have a pending citizenship application. Please wait for approval.'
      };
    }

    // Check if user is already approved
    const kycStatus = await api.query.identityKyc.kycStatuses(account.address);
    if (kycStatus.toString() === 'Approved') {
      console.log('✅ User KYC is already approved');
      return {
        success: false,
        error: 'Your citizenship application is already approved!'
      };
    }

    // Get the injector for signing
    const injector = await web3FromAddress(account.address);

    // Debug logging
    console.log('=== submitKycApplication Debug ===');
    console.log('account.address:', account.address);
    console.log('name:', name);
    console.log('email:', email);
    console.log('ipfsCid:', ipfsCid);
    console.log('notes:', notes);
    console.log('===================================');

    // Ensure ipfsCid is a string
    const cidString = String(ipfsCid);
    if (!cidString || cidString === 'undefined' || cidString === '[object Object]') {
      return { success: false, error: `Invalid IPFS CID received: ${cidString}` };
    }

    // Step 1: Set identity first
    console.log('Step 1: Setting identity...');
    const identityResult = await new Promise<{ success: boolean; error?: string }>((resolve, reject) => {
      api.tx.identityKyc
        .setIdentity(name, email)
        .signAndSend(account.address, { signer: injector.signer }, ({ status, dispatchError, events }) => {
          console.log('Identity transaction status:', status.type);

          if (status.isInBlock || status.isFinalized) {
            if (dispatchError) {
              let errorMessage = 'Identity transaction failed';
              if (dispatchError.isModule) {
                const decoded = api.registry.findMetaError(dispatchError.asModule);
                errorMessage = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`;
              } else {
                errorMessage = dispatchError.toString();
              }
              console.error('Identity transaction error:', errorMessage);
              resolve({ success: false, error: errorMessage });
              return;
            }

            // Check for IdentitySet event
            const identitySetEvent = events.find(({ event }) =>
              event.section === 'identityKyc' && event.method === 'IdentitySet'
            );

            if (identitySetEvent) {
              console.log('✅ Identity set successfully');
              resolve({ success: true });
            } else {
              resolve({ success: true }); // Still consider it success if in block
            }
          }
        })
        .catch((error) => {
          console.error('Failed to sign and send identity transaction:', error);
          reject(error);
        });
    });

    if (!identityResult.success) {
      return identityResult;
    }

    // Step 2: Apply for KYC
    console.log('Step 2: Applying for KYC...');
    const result = await new Promise<{ success: boolean; error?: string; blockHash?: string }>((resolve, reject) => {
      api.tx.identityKyc
        .applyForKyc([cidString], notes)
        .signAndSend(account.address, { signer: injector.signer }, ({ status, dispatchError, events }) => {
          console.log('Transaction status:', status.type);

          if (status.isInBlock || status.isFinalized) {
            if (dispatchError) {
              let errorMessage = 'Transaction failed';

              if (dispatchError.isModule) {
                const decoded = api.registry.findMetaError(dispatchError.asModule);
                errorMessage = `${decoded.section}.${decoded.name}: ${decoded.docs.join(' ')}`;
              } else {
                errorMessage = dispatchError.toString();
              }

              console.error('Transaction error:', errorMessage);
              resolve({ success: false, error: errorMessage });
              return;
            }

            // Check for KycApplied event
            const kycAppliedEvent = events.find(({ event }) =>
              event.section === 'identityKyc' && event.method === 'KycApplied'
            );

            if (kycAppliedEvent) {
              console.log('✅ KYC Application submitted successfully');
              resolve({
                success: true,
                blockHash: status.asInBlock.toString()
              });
            } else {
              console.warn('Transaction included but KycApplied event not found');
              resolve({ success: true });
            }
          }
        })
        .catch((error) => {
          console.error('Failed to sign and send transaction:', error);
          reject(error);
        });
    });

    return result;
  } catch (error: any) {
    console.error('Error submitting KYC application:', error);
    return {
      success: false,
      error: error.message || 'Failed to submit KYC application'
    };
  }
}

/**
 * Subscribe to KYC approval events for an address
 */
export function subscribeToKycApproval(
  api: ApiPromise,
  address: string,
  onApproved: () => void,
  onError?: (error: string) => void
): () => void {
  try {
    if (!api?.query?.system?.events) {
      console.error('Cannot subscribe to events: system.events not available');
      if (onError) onError('Event subscription not available');
      return () => {};
    }

    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    const unsubscribe = api.query.system.events((events: any[]) => {
      // eslint-disable-next-line @typescript-eslint/no-explicit-any
      events.forEach((record: any) => {
        const { event } = record;

        if (event.section === 'identityKyc' && event.method === 'KycApproved') {
          const [approvedAddress] = event.data;

          if (approvedAddress.toString() === address) {
            console.log('✅ KYC Approved for:', address);
            onApproved();
          }
        }
      });
    });

    return unsubscribe as unknown as () => void;
  } catch (error: any) {
    console.error('Error subscribing to KYC approval:', error);
    if (onError) onError(error.message || 'Failed to subscribe to approval events');
    return () => {};
  }
}

// ========================================
// FOUNDER ADDRESS
// ========================================

export const FOUNDER_ADDRESS = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY'; // Satoshi Qazi Muhammed

export interface AuthChallenge {
  message: string;
  nonce: string;
  timestamp: number;
}

/**
 * Generate authentication challenge for existing citizens
 */
export function generateAuthChallenge(tikiNumber: string): AuthChallenge {
  const timestamp = Date.now();
  const nonce = Math.random().toString(36).substring(2, 15);
  const message = `Sign this message to prove you own Citizen #${tikiNumber}`;

  return {
    message,
    nonce: `pezkuwi-auth-${tikiNumber}-${timestamp}-${nonce}`,
    timestamp
  };
}

/**
 * Sign challenge with user's account
 */
export async function signChallenge(
  account: InjectedAccountWithMeta,
  challenge: AuthChallenge
): Promise<string> {
  try {
    const injector = await web3FromAddress(account.address);

    if (!injector?.signer?.signRaw) {
      throw new Error('Signer not available');
    }

    // Sign the challenge nonce
    const signResult = await injector.signer.signRaw({
      address: account.address,
      data: challenge.nonce,
      type: 'bytes'
    });

    return signResult.signature;
  } catch (error) {
    console.error('Failed to sign challenge:', error);
    throw error;
  }
}

/**
 * Verify signature (simplified - in production, verify on backend)
 */
export async function verifySignature(
  signature: string,
  challenge: AuthChallenge,
  address: string
): Promise<boolean> {
  try {
    // For now, just check that signature exists and is valid hex
    // In production, you would verify the signature cryptographically
    if (!signature || signature.length < 10) {
      return false;
    }

    // Basic validation: signature should be hex string starting with 0x
    const isValidHex = /^0x[0-9a-fA-F]+$/.test(signature);

    return isValidHex;
  } catch (error) {
    console.error('Signature verification error:', error);
    return false;
  }
}

export interface CitizenSession {
  tikiNumber: string;
  walletAddress: string;
  sessionToken: string;
  lastAuthenticated: number;
  expiresAt: number;
}

/**
 * Save citizen session (new format)
 */
export function saveCitizenSession(tikiNumber: string, address: string): void;
export function saveCitizenSession(session: CitizenSession): void;
export function saveCitizenSession(tikiNumberOrSession: string | CitizenSession, address?: string): void {
  if (typeof tikiNumberOrSession === 'string') {
    // Old format for backward compatibility
    localStorage.setItem('pezkuwi_citizen_session', JSON.stringify({
      tikiNumber: tikiNumberOrSession,
      address,
      timestamp: Date.now()
    }));
  } else {
    // New format with full session data
    localStorage.setItem('pezkuwi_citizen_session', JSON.stringify(tikiNumberOrSession));
  }
}

/**
 * Get citizen session
 */
export async function getCitizenSession(): Promise<CitizenSession | null> {
  try {
    const sessionData = localStorage.getItem('pezkuwi_citizen_session');
    if (!sessionData) return null;

    const session = JSON.parse(sessionData);

    // Check if it's the new format with expiresAt
    if (session.expiresAt) {
      return session as CitizenSession;
    }

    // Old format - return null to force re-authentication
    return null;
  } catch (error) {
    console.error('Error retrieving citizen session:', error);
    return null;
  }
}

/**
 * Encrypt sensitive data for storage
 */
export function encryptData(data: any): string {
  // In production, use proper encryption
  // For now, base64 encode
  return btoa(JSON.stringify(data));
}

/**
 * Decrypt data
 */
export function decryptData(encrypted: string): any {
  try {
    return JSON.parse(atob(encrypted));
  } catch {
    return null;
  }
}

/**
 * Generate commitment hash for citizenship data
 */
export function generateCommitmentHash(data: any): string {
  const str = JSON.stringify(data);
  // Simple hash for now - in production use proper cryptographic hash
  let hash = 0;
  for (let i = 0; i < str.length; i++) {
    const char = str.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;
    hash = hash & hash;
  }
  return hash.toString(16);
}

/**
 * Generate nullifier hash
 */
export function generateNullifierHash(data: any): string {
  const str = JSON.stringify(data) + Date.now();
  let hash = 0;
  for (let i = 0; i < str.length; i++) {
    const char = str.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;
    hash = hash & hash;
  }
  return 'nullifier_' + hash.toString(16);
}

/**
 * Save citizenship data to local storage
 */
export function saveLocalCitizenshipData(data: any): void {
  const encrypted = encryptData(data);
  localStorage.setItem('pezkuwi_citizenship_data', encrypted);
}

/**
 * Get local citizenship data
 */
export function getLocalCitizenshipData(): any {
  const encrypted = localStorage.getItem('pezkuwi_citizenship_data');
  if (!encrypted) return null;
  return decryptData(encrypted);
}

/**
 * Upload data to IPFS
 */
export async function uploadToIPFS(data: any): Promise<string> {
  // In production, use Pinata or other IPFS service
  // For now, return mock CID
  const mockCID = 'Qm' + Math.random().toString(36).substring(2, 15);
  console.log('Mock IPFS upload:', mockCID, data);
  return mockCID;
}
