// DBIS Governance Service
// Board operations, voting weight calculation, amendment processing

import prisma from '@/shared/database/prisma';
import { Decimal } from '@prisma/client/runtime/library';
import { v4 as uuidv4 } from 'uuid';


export interface VotingWeight {
  sovereignBankId: string;
  liquidityContribution: number;
  stabilityMetrics: number;
  totalWeight: number;
}

export interface ProposalData {
  governanceBodyId: string;
  proposalType: string;
  proposalTitle: string;
  proposalContent: string;
  requiredVoteType: string;
  votingDeadline?: Date;
}

export class GovernanceService {
  /**
   * Calculate voting weight for a sovereign bank
   * Weight = liquidity contribution + stability metrics
   */
  async calculateVotingWeight(sovereignBankId: string): Promise<VotingWeight> {
    // Get sovereign bank
    const bank = await prisma.sovereignBank.findUnique({
      where: { id: sovereignBankId },
      include: {
        liquidityPools: true,
        accounts: true,
      },
    });

    if (!bank) {
      throw new Error(`Sovereign bank not found: ${sovereignBankId}`);
    }

    // Calculate liquidity contribution
    const totalLiquidity = bank.liquidityPools.reduce(
      (sum, pool) => sum + parseFloat(pool.totalLiquidity.toString()),
      0
    );

    // Calculate stability metrics (simplified - would use SRI in production)
    // For now, use a default stability score
    const stabilityMetrics = 50; // Would be calculated from SRI, compliance scores, etc.

    const totalWeight = totalLiquidity + stabilityMetrics;

    return {
      sovereignBankId,
      liquidityContribution: totalLiquidity,
      stabilityMetrics,
      totalWeight,
    };
  }

  /**
   * Get or create governance body
   */
  async getGovernanceBody(bodyType: string) {
    let body = await prisma.governanceBody.findFirst({
      where: { bodyType, status: 'active' },
      include: { members: true },
    });

    if (!body) {
      body = await prisma.governanceBody.create({
        data: {
          id: uuidv4(),
          bodyType,
          name: this.getBodyName(bodyType),
          description: this.getBodyDescription(bodyType),
          votingMechanism: this.getVotingMechanism(bodyType),
          status: 'active',
        },
        include: { members: true },
      });
    }

    return body;
  }

  /**
   * Add member to governance body
   */
  async addMember(
    governanceBodyId: string,
    sovereignBankId: string | null,
    memberName: string,
    memberRole: string
  ) {
    const votingWeight = sovereignBankId
      ? await this.calculateVotingWeight(sovereignBankId)
      : null;

    const member = await prisma.governanceBodyMember.create({
      data: {
        id: uuidv4(),
        governanceBodyId,
        sovereignBankId,
        memberName,
        memberRole,
        votingWeight: votingWeight ? new Decimal(votingWeight.totalWeight) : null,
        status: 'active',
      },
    });

    return member;
  }

  /**
   * Create proposal
   */
  async createProposal(data: ProposalData) {
    const proposal = await prisma.votingRecord.create({
      data: {
        id: uuidv4(),
        proposalId: uuidv4(),
        governanceBodyId: data.governanceBodyId,
        proposalType: data.proposalType,
        proposalTitle: data.proposalTitle,
        proposalContent: data.proposalContent,
        requiredVoteType: data.requiredVoteType,
        votingDeadline: data.votingDeadline,
        status: 'pending',
        votesFor: 0,
        votesAgainst: 0,
        votesAbstain: 0,
        totalVotingWeight: new Decimal(0),
      },
    });

    return proposal;
  }

  /**
   * Cast vote
   */
  async castVote(
    votingRecordId: string,
    memberId: string,
    vote: 'for' | 'against' | 'abstain'
  ) {
    // Get member and voting record
    const member = await prisma.governanceBodyMember.findUnique({
      where: { id: memberId },
    });

    if (!member) {
      throw new Error(`Member not found: ${memberId}`);
    }

    const votingRecord = await prisma.votingRecord.findUnique({
      where: { id: votingRecordId },
      include: { votes: true },
    });

    if (!votingRecord) {
      throw new Error(`Voting record not found: ${votingRecordId}`);
    }

    // Check if already voted
    const existingVote = votingRecord.votes.find((v) => v.memberId === memberId);
    if (existingVote) {
      throw new Error('Member has already voted');
    }

    // Check if voting deadline passed
    if (votingRecord.votingDeadline && votingRecord.votingDeadline < new Date()) {
      throw new Error('Voting deadline has passed');
    }

    const votingWeight = member.votingWeight || new Decimal(0);

    // Create vote
    await prisma.vote.create({
      data: {
        id: uuidv4(),
        votingRecordId,
        memberId,
        vote,
        votingWeight,
      },
    });

    // Update voting record
    const updateData: {
      votesFor?: number;
      votesAgainst?: number;
      votesAbstain?: number;
      totalVotingWeight: Decimal;
      status?: string;
      votedAt?: Date;
    } = {
      totalVotingWeight: votingRecord.totalVotingWeight.plus(votingWeight),
    };

    if (vote === 'for') {
      updateData.votesFor = votingRecord.votesFor + 1;
    } else if (vote === 'against') {
      updateData.votesAgainst = votingRecord.votesAgainst + 1;
    } else {
      updateData.votesAbstain = votingRecord.votesAbstain + 1;
    }

    // Check if voting is complete and determine outcome
    const body = await prisma.governanceBody.findUnique({
      where: { id: votingRecord.governanceBodyId },
      include: { members: true },
    });

    if (body) {
      const totalMembers = body.members.filter((m) => m.status === 'active').length;
      const totalVotes = votingRecord.votes.length + 1; // +1 for this vote

      if (totalVotes >= totalMembers) {
        // All members have voted, determine outcome
        const result = this.evaluateVote(
          votingRecord.requiredVoteType,
          updateData.votesFor || votingRecord.votesFor,
          updateData.votesAgainst || votingRecord.votesAgainst,
          totalMembers,
          updateData.totalVotingWeight
        );

        updateData.status = result.approved ? 'approved' : 'rejected';
        updateData.votedAt = new Date();
      }
    }

    await prisma.votingRecord.update({
      where: { id: votingRecordId },
      data: updateData,
    });

    return { success: true, vote };
  }

  /**
   * Evaluate vote based on required vote type
   */
  private evaluateVote(
    requiredVoteType: string,
    votesFor: number,
    votesAgainst: number,
    totalMembers: number,
    totalVotingWeight: Decimal
  ): { approved: boolean; reason: string } {
    if (requiredVoteType === 'simple_majority') {
      const approved = votesFor > votesAgainst;
      return {
        approved,
        reason: approved
          ? 'Simple majority achieved'
          : 'Simple majority not achieved',
      };
    } else if (requiredVoteType === 'supermajority_2_3') {
      const threshold = Math.ceil((totalMembers * 2) / 3);
      const approved = votesFor >= threshold;
      return {
        approved,
        reason: approved
          ? `Supermajority (2/3) achieved: ${votesFor}/${totalMembers}`
          : `Supermajority (2/3) not achieved: ${votesFor}/${totalMembers} (need ${threshold})`,
      };
    } else if (requiredVoteType === 'unanimous') {
      const approved = votesFor === totalMembers && votesAgainst === 0;
      return {
        approved,
        reason: approved
          ? 'Unanimous approval achieved'
          : `Unanimous approval not achieved: ${votesFor}/${totalMembers}`,
      };
    }

    return { approved: false, reason: 'Unknown vote type' };
  }

  /**
   * Process amendment
   */
  async processAmendment(
    articleNumber: string,
    amendmentContent: string,
    proposalId: string
  ) {
    // Verify proposal was approved
    const proposal = await prisma.votingRecord.findUnique({
      where: { proposalId },
    });

    if (!proposal || proposal.status !== 'approved') {
      throw new Error('Proposal must be approved before processing amendment');
    }

    // Get current article
    const currentArticle = await prisma.constitutionArticle.findFirst({
      where: {
        articleNumber,
        status: 'active',
      },
      orderBy: { version: 'desc' },
    });

    if (!currentArticle) {
      throw new Error(`Article ${articleNumber} not found`);
    }

    // Create new version with amendment
    // In production, this would parse and merge amendment content
    const newContent = `${currentArticle.content}\n\n[Amendment ${new Date().toISOString()}]\n${amendmentContent}`;

    await prisma.constitutionArticle.create({
      data: {
        id: uuidv4(),
        articleNumber,
        articleTitle: currentArticle.articleTitle,
        section: currentArticle.section,
        content: newContent,
        version: currentArticle.version + 1,
        effectiveDate: new Date(),
        metadata: {
          amendmentProposalId: proposalId,
          previousVersion: currentArticle.version,
        },
        status: 'active',
      },
    });

    // Archive previous version
    await prisma.constitutionArticle.updateMany({
      where: {
        articleNumber,
        version: currentArticle.version,
        status: 'active',
      },
      data: {
        status: 'superseded',
      },
    });

    return { success: true, articleNumber, newVersion: currentArticle.version + 1 };
  }

  private getBodyName(bodyType: string): string {
    const names: Record<string, string> = {
      BoardOfGovernors: 'DBIS Board of Governors',
      MSC: 'Monetary & Settlement Council',
      CAA: 'Compliance & Audit Authority',
      SCC: 'Sovereign Crisis Committee',
    };
    return names[bodyType] || bodyType;
  }

  private getBodyDescription(bodyType: string): string {
    const descriptions: Record<string, string> = {
      BoardOfGovernors: 'Supreme governance body with one voting member per SCB',
      MSC: 'Responsible for FX reserve ratios, liquidity obligations, settlement finality rules',
      CAA: 'Supervises FATF, ISO, and ICC compliance, executes audits of any SCB',
      SCC: 'Activated for FX collapse, default events, liquidity freezes',
    };
    return descriptions[bodyType] || '';
  }

  private getVotingMechanism(bodyType: string): string {
    const mechanisms: Record<string, string> = {
      BoardOfGovernors: 'weighted_voting',
      MSC: 'supermajority_2_3',
      CAA: 'simple_majority',
      SCC: 'unanimous',
    };
    return mechanisms[bodyType] || 'simple_majority';
  }
}

export const governanceService = new GovernanceService();

