-- Auto-Approval Onboarding System Migration
-- This migration adds the database schema for auto-approval rules and account status tracking

-- Create auto-approval rules table
CREATE TABLE IF NOT EXISTS auto_approval_rules (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  rule_name VARCHAR(100) NOT NULL,
  email_domain VARCHAR(255),
  business_type VARCHAR(50),
  minimum_score INTEGER DEFAULT 0,
  is_active BOOLEAN DEFAULT true,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Add account status and approval tracking to organizations
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS account_status VARCHAR(50) DEFAULT 'pending_approval';
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS approval_score INTEGER DEFAULT 0;
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS auto_approved BOOLEAN DEFAULT false;
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS approved_at TIMESTAMP WITH TIME ZONE;
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS approved_by UUID REFERENCES users(id);
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS approval_reason TEXT;

-- Add Stripe onboarding tracking
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS stripe_onboarding_status VARCHAR(50) DEFAULT 'not_started';
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS stripe_onboarding_url TEXT;
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS stripe_details_submitted BOOLEAN DEFAULT false;
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS stripe_charges_enabled BOOLEAN DEFAULT false;
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS stripe_payouts_enabled BOOLEAN DEFAULT false;
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS onboarding_completed_at TIMESTAMP WITH TIME ZONE;

-- Add business profile fields for better approval scoring
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS business_type VARCHAR(50);
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS business_description TEXT;
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS website_url TEXT;
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS phone_number VARCHAR(20);
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS address_line1 TEXT;
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS address_line2 TEXT;
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS city VARCHAR(100);
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS state VARCHAR(50);
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS postal_code VARCHAR(20);
ALTER TABLE organizations ADD COLUMN IF NOT EXISTS country VARCHAR(2) DEFAULT 'US';

-- Create organization onboarding progress table
CREATE TABLE IF NOT EXISTS organization_onboarding_progress (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  organization_id UUID REFERENCES organizations(id) NOT NULL,
  step_key VARCHAR(100) NOT NULL,
  status VARCHAR(20) DEFAULT 'pending',
  completed_at TIMESTAMP WITH TIME ZONE,
  data JSONB,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
  UNIQUE(organization_id, step_key)
);

-- Create audit log for approval actions
CREATE TABLE IF NOT EXISTS approval_audit_log (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  organization_id UUID REFERENCES organizations(id) NOT NULL,
  action VARCHAR(50) NOT NULL, -- 'auto_approved', 'manually_approved', 'rejected'
  actor_id UUID REFERENCES users(id), -- NULL for auto-approval
  reason TEXT,
  previous_status VARCHAR(50),
  new_status VARCHAR(50),
  metadata JSONB,
  created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Insert default auto-approval rules
INSERT INTO auto_approval_rules (rule_name, email_domain, minimum_score, is_active) VALUES
('Trusted Educational Domains', 'edu', 80, true),
('Government Organizations', 'gov', 90, true),
('Known Venue Partners', 'eventbrite.com', 85, true),
('High Score Threshold', NULL, 95, true)
ON CONFLICT DO NOTHING;

-- Add indexes for performance
CREATE INDEX IF NOT EXISTS idx_organizations_account_status ON organizations(account_status);
CREATE INDEX IF NOT EXISTS idx_organizations_approval_score ON organizations(approval_score);
CREATE INDEX IF NOT EXISTS idx_organizations_stripe_onboarding_status ON organizations(stripe_onboarding_status);
CREATE INDEX IF NOT EXISTS idx_auto_approval_rules_active ON auto_approval_rules(is_active);
CREATE INDEX IF NOT EXISTS idx_onboarding_progress_org_id ON organization_onboarding_progress(organization_id);
CREATE INDEX IF NOT EXISTS idx_approval_audit_log_org_id ON approval_audit_log(organization_id);
CREATE INDEX IF NOT EXISTS idx_approval_audit_log_created_at ON approval_audit_log(created_at);

-- Create function to update updated_at timestamps
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at = NOW();
  RETURN NEW;
END;
$$ language 'plpgsql';

-- Add triggers for updated_at
CREATE TRIGGER update_auto_approval_rules_updated_at 
  BEFORE UPDATE ON auto_approval_rules 
  FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

CREATE TRIGGER update_onboarding_progress_updated_at 
  BEFORE UPDATE ON organization_onboarding_progress 
  FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- RLS Policies for new tables
ALTER TABLE auto_approval_rules ENABLE ROW LEVEL SECURITY;
ALTER TABLE organization_onboarding_progress ENABLE ROW LEVEL SECURITY;
ALTER TABLE approval_audit_log ENABLE ROW LEVEL SECURITY;

-- Auto-approval rules: Only admins can access
CREATE POLICY "Admins can manage auto-approval rules" ON auto_approval_rules
  FOR ALL USING (auth.uid() IN (SELECT id FROM users WHERE role = 'admin'));

-- Onboarding progress: Users can access their own organization's progress
CREATE POLICY "Users can access their organization's onboarding progress" ON organization_onboarding_progress
  FOR ALL USING (
    organization_id IN (
      SELECT organization_id FROM users WHERE id = auth.uid()
    )
  );

-- Audit log: Users can read their own organization's audit log, admins can read all
CREATE POLICY "Users can read their organization's audit log" ON approval_audit_log
  FOR SELECT USING (
    organization_id IN (
      SELECT organization_id FROM users WHERE id = auth.uid()
    ) OR auth.uid() IN (SELECT id FROM users WHERE role = 'admin')
  );

-- Only admins can write to audit log
CREATE POLICY "Only admins can write to audit log" ON approval_audit_log
  FOR INSERT WITH CHECK (auth.uid() IN (SELECT id FROM users WHERE role = 'admin'));

-- Create function to calculate approval score
CREATE OR REPLACE FUNCTION calculate_approval_score(org_id UUID)
RETURNS INTEGER AS $$
DECLARE
  score INTEGER DEFAULT 0;
  org_record RECORD;
  user_record RECORD;
BEGIN
  -- Get organization and user data
  SELECT * INTO org_record FROM organizations WHERE id = org_id;
  SELECT * INTO user_record FROM users WHERE organization_id = org_id AND role = 'organizer' LIMIT 1;
  
  IF org_record IS NULL OR user_record IS NULL THEN
    RETURN 0;
  END IF;
  
  -- Base score for having an organization
  score := 10;
  
  -- Email domain scoring
  IF user_record.email LIKE '%.edu' THEN
    score := score + 40;
  ELSIF user_record.email LIKE '%.gov' THEN
    score := score + 50;
  ELSIF user_record.email LIKE '%.org' THEN
    score := score + 20;
  END IF;
  
  -- Business information completeness
  IF org_record.business_type IS NOT NULL THEN
    score := score + 10;
  END IF;
  
  IF org_record.business_description IS NOT NULL AND LENGTH(org_record.business_description) > 50 THEN
    score := score + 15;
  END IF;
  
  IF org_record.website_url IS NOT NULL THEN
    score := score + 10;
  END IF;
  
  IF org_record.phone_number IS NOT NULL THEN
    score := score + 5;
  END IF;
  
  IF org_record.address_line1 IS NOT NULL THEN
    score := score + 10;
  END IF;
  
  -- Update the organization's approval score
  UPDATE organizations SET approval_score = score WHERE id = org_id;
  
  RETURN score;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Create function to check if organization should be auto-approved
CREATE OR REPLACE FUNCTION should_auto_approve(org_id UUID)
RETURNS BOOLEAN AS $$
DECLARE
  score INTEGER;
  org_record RECORD;
  user_record RECORD;
  rule_record RECORD;
BEGIN
  -- Calculate current score
  score := calculate_approval_score(org_id);
  
  -- Get organization and user data
  SELECT * INTO org_record FROM organizations WHERE id = org_id;
  SELECT * INTO user_record FROM users WHERE organization_id = org_id AND role = 'organizer' LIMIT 1;
  
  -- Check domain-specific rules
  FOR rule_record IN SELECT * FROM auto_approval_rules WHERE is_active = true AND email_domain IS NOT NULL LOOP
    IF user_record.email LIKE '%' || rule_record.email_domain THEN
      IF score >= rule_record.minimum_score THEN
        RETURN true;
      END IF;
    END IF;
  END LOOP;
  
  -- Check general score threshold rules
  FOR rule_record IN SELECT * FROM auto_approval_rules WHERE is_active = true AND email_domain IS NULL LOOP
    IF score >= rule_record.minimum_score THEN
      RETURN true;
    END IF;
  END LOOP;
  
  RETURN false;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Create function to process auto-approval
CREATE OR REPLACE FUNCTION process_auto_approval(org_id UUID)
RETURNS BOOLEAN AS $$
DECLARE
  should_approve BOOLEAN;
  current_status VARCHAR(50);
BEGIN
  -- Get current status
  SELECT account_status INTO current_status FROM organizations WHERE id = org_id;
  
  -- Only process if currently pending approval
  IF current_status != 'pending_approval' THEN
    RETURN false;
  END IF;
  
  -- Check if should auto-approve
  should_approve := should_auto_approve(org_id);
  
  IF should_approve THEN
    -- Update organization status
    UPDATE organizations SET 
      account_status = 'approved',
      auto_approved = true,
      approved_at = NOW(),
      approval_reason = 'Auto-approved based on scoring rules'
    WHERE id = org_id;
    
    -- Log the approval
    INSERT INTO approval_audit_log (
      organization_id, 
      action, 
      actor_id, 
      reason, 
      previous_status, 
      new_status,
      metadata
    ) VALUES (
      org_id,
      'auto_approved',
      NULL,
      'Auto-approved based on scoring rules',
      'pending_approval',
      'approved',
      jsonb_build_object('approval_score', (SELECT approval_score FROM organizations WHERE id = org_id))
    );
    
    RETURN true;
  END IF;
  
  RETURN false;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

-- Create trigger to process auto-approval when organization is created or updated
CREATE OR REPLACE FUNCTION trigger_auto_approval_check()
RETURNS TRIGGER AS $$
BEGIN
  -- Only process if account_status is pending_approval
  IF NEW.account_status = 'pending_approval' THEN
    PERFORM process_auto_approval(NEW.id);
  END IF;
  
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- Add trigger to organizations table
CREATE TRIGGER check_auto_approval_on_update
  AFTER UPDATE ON organizations
  FOR EACH ROW
  EXECUTE FUNCTION trigger_auto_approval_check();

-- Create view for admin dashboard
CREATE OR REPLACE VIEW admin_pending_approvals AS
SELECT 
  o.id,
  o.name,
  o.account_status,
  o.approval_score,
  o.business_type,
  o.business_description,
  o.created_at,
  u.email as owner_email,
  u.name as owner_name,
  calculate_approval_score(o.id) as current_score,
  should_auto_approve(o.id) as can_auto_approve
FROM organizations o
JOIN users u ON u.organization_id = o.id AND u.role = 'organizer'
WHERE o.account_status = 'pending_approval'
ORDER BY o.created_at DESC;

-- Grant permissions to authenticated users
GRANT SELECT ON admin_pending_approvals TO authenticated;
GRANT EXECUTE ON FUNCTION calculate_approval_score TO authenticated;
GRANT EXECUTE ON FUNCTION should_auto_approve TO authenticated;
GRANT EXECUTE ON FUNCTION process_auto_approval TO authenticated;