-- =====================================================
-- P2P Fiat Trading System
-- Production-grade schema with full security & audit
-- =====================================================

-- Enable required extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

-- =====================================================
-- PAYMENT METHODS TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS public.payment_methods (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  currency TEXT NOT NULL CHECK (currency IN ('TRY', 'IQD', 'IRR', 'EUR', 'USD')),
  country TEXT NOT NULL,
  method_name TEXT NOT NULL,
  method_type TEXT NOT NULL CHECK (method_type IN ('bank', 'mobile_payment', 'cash', 'crypto_exchange')),
  logo_url TEXT,
  fields JSONB NOT NULL,
  validation_rules JSONB DEFAULT '{}',
  is_active BOOLEAN DEFAULT true,
  display_order INT DEFAULT 0,
  min_trade_amount NUMERIC DEFAULT 0,
  max_trade_amount NUMERIC,
  processing_time_minutes INT DEFAULT 60,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  
  CONSTRAINT unique_payment_method UNIQUE (currency, method_name)
);

CREATE INDEX IF NOT EXISTS idx_payment_methods_currency_active ON public.payment_methods(currency, is_active);
CREATE INDEX IF NOT EXISTS idx_payment_methods_type ON public.payment_methods(method_type);

-- =====================================================
-- P2P FIAT OFFERS TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS public.p2p_fiat_offers (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  seller_id UUID NOT NULL REFERENCES auth.users(id) ON DELETE CASCADE,
  seller_wallet TEXT NOT NULL,
  
  -- Crypto side
  token TEXT NOT NULL CHECK (token IN ('HEZ', 'PEZ')),
  amount_crypto NUMERIC NOT NULL CHECK (amount_crypto > 0),
  
  -- Fiat side
  fiat_currency TEXT NOT NULL CHECK (fiat_currency IN ('TRY', 'IQD', 'IRR', 'EUR', 'USD')),
  fiat_amount NUMERIC NOT NULL CHECK (fiat_amount > 0),
  price_per_unit NUMERIC GENERATED ALWAYS AS (fiat_amount / amount_crypto) STORED,
  
  -- Payment details
  payment_method_id UUID NOT NULL REFERENCES public.payment_methods(id),
  payment_details_encrypted TEXT NOT NULL, -- PGP encrypted JSONB
  
  -- Terms
  min_order_amount NUMERIC CHECK (min_order_amount > 0 AND min_order_amount <= amount_crypto),
  max_order_amount NUMERIC CHECK (max_order_amount >= min_order_amount AND max_order_amount <= amount_crypto),
  time_limit_minutes INT DEFAULT 30 CHECK (time_limit_minutes BETWEEN 15 AND 120),
  auto_reply_message TEXT,
  
  -- Restrictions
  min_buyer_completed_trades INT DEFAULT 0,
  min_buyer_reputation INT DEFAULT 0,
  blocked_users UUID[] DEFAULT '{}',
  
  -- Status
  status TEXT NOT NULL DEFAULT 'open' CHECK (status IN ('open', 'paused', 'locked', 'completed', 'cancelled')),
  remaining_amount NUMERIC NOT NULL CHECK (remaining_amount >= 0 AND remaining_amount <= amount_crypto),
  
  -- Escrow tracking
  escrow_tx_hash TEXT,
  escrow_locked_at TIMESTAMPTZ,
  
  -- Timestamps
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  expires_at TIMESTAMPTZ DEFAULT NOW() + INTERVAL '7 days',
  
  CONSTRAINT check_order_amounts CHECK (
    (min_order_amount IS NULL AND max_order_amount IS NULL) OR
    (min_order_amount IS NOT NULL AND max_order_amount IS NOT NULL)
  )
);

CREATE INDEX IF NOT EXISTS idx_p2p_offers_seller ON public.p2p_fiat_offers(seller_id);
CREATE INDEX IF NOT EXISTS idx_p2p_offers_currency ON public.p2p_fiat_offers(fiat_currency, token);
CREATE INDEX IF NOT EXISTS idx_p2p_offers_status ON public.p2p_fiat_offers(status)WHERE status IN ('open', 'paused');
CREATE INDEX IF NOT EXISTS idx_p2p_offers_active ON public.p2p_fiat_offers(status, fiat_currency, token) 
  WHERE status = 'open' AND remaining_amount > 0;

-- =====================================================
-- P2P FIAT TRADES TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS public.p2p_fiat_trades (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  offer_id UUID NOT NULL REFERENCES public.p2p_fiat_offers(id) ON DELETE CASCADE,
  seller_id UUID NOT NULL REFERENCES auth.users(id),
  buyer_id UUID NOT NULL REFERENCES auth.users(id),
  buyer_wallet TEXT NOT NULL,
  
  -- Trade amounts
  crypto_amount NUMERIC NOT NULL CHECK (crypto_amount > 0),
  fiat_amount NUMERIC NOT NULL CHECK (fiat_amount > 0),
  price_per_unit NUMERIC NOT NULL,
  
  -- Escrow
  escrow_locked_amount NUMERIC NOT NULL,
  escrow_locked_at TIMESTAMPTZ,
  escrow_release_tx_hash TEXT,
  escrow_released_at TIMESTAMPTZ,
  
  -- Payment tracking
  buyer_marked_paid_at TIMESTAMPTZ,
  buyer_payment_proof_url TEXT, -- IPFS hash
  seller_confirmed_at TIMESTAMPTZ,
  
  -- Chat messages (encrypted)
  chat_messages JSONB DEFAULT '[]',
  
  -- Status
  status TEXT NOT NULL DEFAULT 'pending' CHECK (
    status IN ('pending', 'payment_sent', 'completed', 'cancelled', 'disputed', 'refunded')
  ),
  
  -- Deadlines
  payment_deadline TIMESTAMPTZ NOT NULL,
  confirmation_deadline TIMESTAMPTZ,
  
  -- Cancellation/Dispute
  cancelled_by UUID REFERENCES auth.users(id),
  cancellation_reason TEXT,
  dispute_id UUID,
  
  -- Timestamps
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  completed_at TIMESTAMPTZ,
  
  CONSTRAINT different_users CHECK (seller_id != buyer_id)
);

CREATE INDEX IF NOT EXISTS idx_p2p_trades_offer ON public.p2p_fiat_trades(offer_id);
CREATE INDEX IF NOT EXISTS idx_p2p_trades_seller ON public.p2p_fiat_trades(seller_id);
CREATE INDEX IF NOT EXISTS idx_p2p_trades_buyer ON public.p2p_fiat_trades(buyer_id);
CREATE INDEX IF NOT EXISTS idx_p2p_trades_status ON public.p2p_fiat_trades(status);
CREATE INDEX IF NOT EXISTS idx_p2p_trades_deadlines ON public.p2p_fiat_trades(payment_deadline, confirmation_deadline) 
 WHERE status IN ('pending', 'payment_sent');

-- =====================================================
-- P2P DISPUTES TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS public.p2p_fiat_disputes (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  trade_id UUID NOT NULL REFERENCES public.p2p_fiat_trades(id) ON DELETE CASCADE,
  opened_by UUID NOT NULL REFERENCES auth.users(id),
  
  -- Dispute details
  reason TEXT NOT NULL CHECK (LENGTH(reason) >= 20),
  category TEXT NOT NULL CHECK (
    category IN ('payment_not_received', 'wrong_amount', 'fake_payment_proof', 'other')
  ),
  evidence_urls TEXT[] DEFAULT '{}', -- IPFS hashes
  additional_info JSONB DEFAULT '{}',
  
  -- Moderator assignment
  assigned_moderator_id UUID REFERENCES auth.users(id),
  assigned_at TIMESTAMPTZ,
  
  -- Resolution
  decision TEXT CHECK (decision IN ('release_to_buyer', 'refund_to_seller', 'split', 'escalate')),
  decision_reasoning TEXT,
  resolved_at TIMESTAMPTZ,
  
  -- Status
  status TEXT NOT NULL DEFAULT 'open' CHECK (
    status IN ('open', 'under_review', 'resolved', 'escalated', 'closed')
  ),
  
  -- Timestamps
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  
  CONSTRAINT one_dispute_per_trade UNIQUE (trade_id)
);

CREATE INDEX IF NOT EXISTS idx_disputes_trade ON public.p2p_fiat_disputes(trade_id);
CREATE INDEX IF NOT EXISTS idx_disputes_status ON public.p2p_fiat_disputes(status)WHERE status IN ('open', 'under_review');
CREATE INDEX IF NOT EXISTS idx_disputes_moderator ON public.p2p_fiat_disputes(assigned_moderator_id) WHERE status = 'under_review';

-- =====================================================
-- P2P REPUTATION TABLE
-- =====================================================
CREATE TABLE IF NOT EXISTS public.p2p_reputation (
  user_id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE,
  
  -- Trade statistics
  total_trades INT DEFAULT 0 CHECK (total_trades >= 0),
  completed_trades INT DEFAULT 0 CHECK (completed_trades >= 0 AND completed_trades <= total_trades),
  cancelled_trades INT DEFAULT 0 CHECK (cancelled_trades >= 0),
  disputed_trades INT DEFAULT 0 CHECK (disputed_trades >= 0),
  
  -- Role statistics
  total_as_seller INT DEFAULT 0 CHECK (total_as_seller >= 0),
  total_as_buyer INT DEFAULT 0 CHECK (total_as_buyer >= 0),
  
  -- Volume
  total_volume_usd NUMERIC DEFAULT 0 CHECK (total_volume_usd >= 0),
  
  -- Timing metrics
  avg_payment_time_minutes INT,
  avg_confirmation_time_minutes INT,
  
  -- Reputation score (0-1000)
  reputation_score INT DEFAULT 100 CHECK (reputation_score BETWEEN 0 AND 1000),
  trust_level TEXT DEFAULT 'new' CHECK (
    trust_level IN ('new', 'basic', 'intermediate', 'advanced', 'verified')
  ),
  
  -- Badges
  verified_merchant BOOLEAN DEFAULT false,
  fast_trader BOOLEAN DEFAULT false,
  
  -- Restrictions
  is_restricted BOOLEAN DEFAULT false,
  restriction_reason TEXT,
  restricted_until TIMESTAMPTZ,
  
  -- Timestamps
  first_trade_at TIMESTAMPTZ,
  last_trade_at TIMESTAMPTZ,
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_reputation_score ON public.p2p_reputation(reputation_score DESC);
CREATE INDEX IF NOT EXISTS idx_reputation_verified ON public.p2p_reputation(verified_merchant) WHERE verified_merchant = true;

-- =====================================================
-- PLATFORM ESCROW TRACKING
-- =====================================================
CREATE TABLE IF NOT EXISTS public.platform_escrow_balance (
  token TEXT PRIMARY KEY CHECK (token IN ('HEZ', 'PEZ')),
  total_locked NUMERIC DEFAULT 0 CHECK (total_locked >= 0),
  hot_wallet_address TEXT NOT NULL,
  last_audit_at TIMESTAMPTZ,
  last_audit_blockchain_balance NUMERIC,
  discrepancy NUMERIC GENERATED ALWAYS AS (last_audit_blockchain_balance - total_locked) STORED,
  updated_at TIMESTAMPTZ DEFAULT NOW()
);

-- =====================================================
-- AUDIT LOG
-- =====================================================
CREATE TABLE IF NOT EXISTS public.p2p_audit_log (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id UUID REFERENCES auth.users(id),
  action TEXT NOT NULL,
  entity_type TEXT NOT NULL CHECK (entity_type IN ('offer', 'trade', 'dispute')),
  entity_id UUID NOT NULL,
  details JSONB DEFAULT '{}',
  ip_address INET,
  user_agent TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_audit_log_user ON public.p2p_audit_log(user_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_audit_log_entity ON public.p2p_audit_log(entity_type, entity_id);
CREATE INDEX IF NOT EXISTS idx_audit_log_created ON public.p2p_audit_log(created_at DESC);

-- =====================================================
-- TRIGGERS FOR UPDATED_AT
-- =====================================================
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at = NOW();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS update_payment_methods_updated_at ON public.payment_methods;
CREATE TRIGGER update_payment_methods_updated_at BEFORE UPDATE ON public.payment_methods
  FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

DROP TRIGGER IF EXISTS update_p2p_offers_updated_at ON public.p2p_fiat_offers;
CREATE TRIGGER update_p2p_offers_updated_at BEFORE UPDATE ON public.p2p_fiat_offers
  FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

DROP TRIGGER IF EXISTS update_p2p_trades_updated_at ON public.p2p_fiat_trades;
CREATE TRIGGER update_p2p_trades_updated_at BEFORE UPDATE ON public.p2p_fiat_trades
  FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

DROP TRIGGER IF EXISTS update_p2p_disputes_updated_at ON public.p2p_fiat_disputes;
CREATE TRIGGER update_p2p_disputes_updated_at BEFORE UPDATE ON public.p2p_fiat_disputes
  FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- =====================================================
-- RLS POLICIES
-- =====================================================

-- Payment Methods: Public read
ALTER TABLE public.payment_methods ENABLE ROW LEVEL SECURITY;
CREATE POLICY "payment_methods_public_read" ON public.payment_methods
  FOR SELECT USING (is_active = true);

CREATE POLICY "payment_methods_admin_all" ON public.payment_methods
  FOR ALL USING (
    EXISTS (SELECT 1 FROM public.admin_roles WHERE user_id = auth.uid())
  );

-- P2P Offers: Public read active, sellers manage own
ALTER TABLE public.p2p_fiat_offers ENABLE ROW LEVEL SECURITY;

CREATE POLICY "offers_public_read_active" ON public.p2p_fiat_offers
  FOR SELECT USING (
    status IN ('open', 'paused') AND 
    remaining_amount > 0 AND 
    expires_at > NOW()
  );

CREATE POLICY "offers_seller_read_own" ON public.p2p_fiat_offers
  FOR SELECT USING (seller_id = auth.uid());

CREATE POLICY "offers_seller_insert" ON public.p2p_fiat_offers
  FOR INSERT WITH CHECK (seller_id = auth.uid());

CREATE POLICY "offers_seller_update_own" ON public.p2p_fiat_offers
  FOR UPDATE USING (seller_id = auth.uid());

CREATE POLICY "offers_seller_delete_own" ON public.p2p_fiat_offers
  FOR DELETE USING (seller_id = auth.uid() AND status IN ('open', 'paused'));

-- P2P Trades: Parties can view/update own trades
ALTER TABLE public.p2p_fiat_trades ENABLE ROW LEVEL SECURITY;

CREATE POLICY "trades_parties_read" ON public.p2p_fiat_trades
  FOR SELECT USING (seller_id = auth.uid() OR buyer_id = auth.uid());

CREATE POLICY "trades_buyer_insert" ON public.p2p_fiat_trades
  FOR INSERT WITH CHECK (buyer_id = auth.uid());

CREATE POLICY "trades_parties_update" ON public.p2p_fiat_trades
  FOR UPDATE USING (seller_id = auth.uid() OR buyer_id = auth.uid());

-- Disputes: Parties and moderators
ALTER TABLE public.p2p_fiat_disputes ENABLE ROW LEVEL SECURITY;

CREATE POLICY "disputes_parties_read" ON public.p2p_fiat_disputes
  FOR SELECT USING (
    opened_by = auth.uid() OR
    EXISTS (
      SELECT 1 FROM public.p2p_fiat_trades t 
      WHERE t.id = trade_id AND (t.seller_id = auth.uid() OR t.buyer_id = auth.uid())
    )
  );

CREATE POLICY "disputes_moderators_read" ON public.p2p_fiat_disputes
  FOR SELECT USING (
    EXISTS (
      SELECT 1 FROM public.admin_roles 
      WHERE user_id = auth.uid() AND role IN ('moderator', 'admin')
    )
  );

CREATE POLICY "disputes_parties_insert" ON public.p2p_fiat_disputes
  FOR INSERT WITH CHECK (
    opened_by = auth.uid() AND
    EXISTS (
      SELECT 1 FROM public.p2p_fiat_trades t
      WHERE t.id = trade_id AND (t.seller_id = auth.uid() OR t.buyer_id = auth.uid())
    )
  );

-- Reputation: Public read, system updates
ALTER TABLE public.p2p_reputation ENABLE ROW LEVEL SECURITY;

CREATE POLICY "reputation_public_read" ON public.p2p_reputation
  FOR SELECT USING (true);

-- Escrow: Admin only
ALTER TABLE public.platform_escrow_balance ENABLE ROW LEVEL SECURITY;

CREATE POLICY "escrow_admin_only" ON public.platform_escrow_balance
  FOR ALL USING (
    EXISTS (SELECT 1 FROM public.admin_roles WHERE user_id = auth.uid())
  );

-- Audit log: Own + admins
ALTER TABLE public.p2p_audit_log ENABLE ROW LEVEL SECURITY;

CREATE POLICY "audit_user_read_own" ON public.p2p_audit_log
  FOR SELECT USING (user_id = auth.uid());

CREATE POLICY "audit_admin_read_all" ON public.p2p_audit_log
  FOR SELECT USING (
    EXISTS (SELECT 1 FROM public.admin_roles WHERE user_id = auth.uid())
  );
